Commit 1e7fb04a authored by Deokseong "David" Kim's avatar Deokseong "David" Kim

Script update to run multiple types of USRP to send multiple strings

parent feec7ef4
...@@ -7,14 +7,18 @@ ...@@ -7,14 +7,18 @@
# --user flags. The -r will enable this simulation to be repeated # --user flags. The -r will enable this simulation to be repeated
# three times. # three times.
# #
# python3 run_sl_test.py --user account --host 10.1.1.68 -r 3 # python3 run_sl_test.py --user account --host 10.1.1.68 -r 3 --test usrp
# #
# The following is an example to run just a Sidelink Nearby UE. # The following is an example to run just a Sidelink Nearby UE.
# By specifying -l nearby, only the nearby UE will be launched # By specifying -l nearby, only the nearby UE will be launched
# on the machine specified by the --host and --user flags. # on the machine specified by the --host and --user flags.
# The -r will enable this simulation to be repeated two times. # The -r will enable this simulation to be repeated two times.
# #
# python3 run_sl_test.py -l nearby --user account --host 10.1.1.68 -r 2 # python3 run_sl_test.py -l nearby --user account --host 10.1.1.68 -r 2 --test usrp
#
# To run usrp test in the net 1 speficifed in sl_cmds.txt, the following will be used.
#
# python3 run_sl_test.py --test usrp --net 1
# #
# See `--help` for more information. # See `--help` for more information.
# #
...@@ -26,9 +30,10 @@ import logging ...@@ -26,9 +30,10 @@ import logging
import time import time
import re import re
import glob import glob
import subprocess import subprocess, shlex
from subprocess import Popen from subprocess import Popen
from subprocess import check_output from subprocess import check_output
from collections import defaultdict
import threading import threading
from typing import Dict from typing import Dict
from queue import Queue from queue import Queue
...@@ -43,11 +48,11 @@ parser = argparse.ArgumentParser(description=""" ...@@ -43,11 +48,11 @@ parser = argparse.ArgumentParser(description="""
Automated tests for 5G NR Sidelink simulations Automated tests for 5G NR Sidelink simulations
""") """)
parser.add_argument('--launch', '-l', default='both', choices='syncref nearby both'.split(), help=""" parser.add_argument('--launch', '-l', default='all', choices='syncref nearby all'.split(), help="""
Sidelink UE type to launch test scenario (default: %(default)s) Sidelink UE type to launch test scenario (default: %(default)s)
""") """)
parser.add_argument('--host', default='10.1.1.61', type=str, help=""" parser.add_argument('--host', default='', type=str, help="""
Nearby Host IP (default: %(default)s) Nearby Host IP (default: %(default)s)
""") """)
...@@ -55,59 +60,63 @@ parser.add_argument('--user', '-u', default=os.environ.get('USER'), type=str, he ...@@ -55,59 +60,63 @@ parser.add_argument('--user', '-u', default=os.environ.get('USER'), type=str, he
User id in Nearby Host (default: %(default)s) User id in Nearby Host (default: %(default)s)
""") """)
parser.add_argument('--att', type=int, default=-1, help="""
Attenuation value
""")
parser.add_argument('--att-host', default='10.1.1.78', type=str, help=""" parser.add_argument('--att-host', default='10.1.1.78', type=str, help="""
Host IP for adjusting attenuation (default: %(default)s) Host IP for adjusting attenuation (default: %(default)s)
""") """)
parser.add_argument('--att-user', default='zaid', type=str, help=""" parser.add_argument('--att-user', default=os.environ.get('USER'), type=str, help="""
User id for adjusting attenuation (default: %(default)s) User id for adjusting attenuation (default: %(default)s)
""") """)
parser.add_argument('--repeat', '-r', default=1, type=int, help="""
The number of repeated test iterations (default: %(default)s)
""")
parser.add_argument('--basic', '-b', action='store_true', help=""" parser.add_argument('--basic', '-b', action='store_true', help="""
Basic test with basic shell commands Basic test with basic shell commands
""") """)
parser.add_argument('--message', '-m', type=str, default='EpiScience', help=""" parser.add_argument('--commands', default='sl_cmds.txt', help="""
The message to send from SyncRef UE to Nearby UE The USRP Commands .txt file (default: %(default)s)
""") """)
parser.add_argument('--mcs', default=9, type=int, help=""" parser.add_argument('--compress', action='store_true', help="""
The default mcs value (default: %(default)s) Compress the log files in the --log-dir
""") """)
parser.add_argument('--commands', default='sl_cmds.txt', help=""" parser.add_argument('--dest', type=str, default='', help="""
The USRP Commands .txt file (default: %(default)s) Destination node identifier for sidelink communication (default: %(default)s)
""") """)
parser.add_argument('--duration', '-d', metavar='SECONDS', type=int, default=20, help=""" parser.add_argument('--duration', '-d', metavar='SECONDS', type=int, default=20, help="""
How long to run the test before stopping to examine the logs How long to run the test before stopping to examine the logs
""") """)
parser.add_argument('--att', type=int, default=-1, help=""" parser.add_argument('--log-dir', default=HOME_DIR, help="""
Attenuation value Where to store log files
""") """)
parser.add_argument('--nid1', type=int, default=10, help=""" parser.add_argument('--message', '-m', type=str, default='', help="""
Nid1 value The message to send from SyncRef UE to Nearby UE
""") """)
parser.add_argument('--nid2', type=int, default=1, help=""" parser.add_argument('--mcs', default=0, type=int, help="""
Nid2 value The default mcs value (default: %(default)s)
""") """)
parser.add_argument('--log-dir', default=HOME_DIR, help=""" parser.add_argument('--net', '-n', type=int, default=1, help="""
Where to store log files Network identifier for sidelink communication (default: %(default)s)
""") """)
parser.add_argument('--compress', action='store_true', help=""" parser.add_argument('--nid1', type=int, default=10, help="""
Compress the log files in the --log-dir Nid1 value
""") """)
parser.add_argument('--no-run', '-n', action='store_true', help=""" parser.add_argument('--nid2', type=int, default=1, help="""
Nid2 value
""")
parser.add_argument('--no-run', action='store_true', help="""
Don't run the test, only examine the logs in the --log-dir Don't run the test, only examine the logs in the --log-dir
directory from a previous run of the test directory from a previous run of the test
""") """)
...@@ -116,6 +125,10 @@ parser.add_argument('--debug', action='store_true', help=""" ...@@ -116,6 +125,10 @@ parser.add_argument('--debug', action='store_true', help="""
Enable debug logging (for this script only) Enable debug logging (for this script only)
""") """)
parser.add_argument('--repeat', '-r', default=1, type=int, help="""
The number of repeated test iterations (default: %(default)s)
""")
parser.add_argument('--save', default=None, help=""" parser.add_argument('--save', default=None, help="""
The default Python log result with .txt extension (default: %(default)s) The default Python log result with .txt extension (default: %(default)s)
""") """)
...@@ -124,8 +137,8 @@ parser.add_argument('--sci2', action='store_true', help=""" ...@@ -124,8 +137,8 @@ parser.add_argument('--sci2', action='store_true', help="""
Enable SCI2 log parsing (this will grep the logs for the SCI2 payload) Enable SCI2 log parsing (this will grep the logs for the SCI2 payload)
""") """)
parser.add_argument('--test', '-t', default='usrp_n310', choices='psbchsim psschsim rfsim usrp_b210 usrp_n310'.split(), help=""" parser.add_argument('--test', '-t', default='rfsim', choices='rfsim usrp psbchsim psschsim'.split(), help="""
The kind of test scenario to run. The options include psbchsim, psschsim, rfsim, or usrp_b210 usrp_n310. (default: %(default)s) The kind of test scenario to run. The options include rfsim, usrp, psbchsim, and psschsim. (default: %(default)s)
""") """)
parser.add_argument('--snr', default='0.0', help=""" parser.add_argument('--snr', default='0.0', help="""
...@@ -163,7 +176,7 @@ class Command: ...@@ -163,7 +176,7 @@ class Command:
self.parse_commands() self.parse_commands()
def check_user(self) -> None: def check_user(self) -> None:
if OPTS.test != 'usrp': if 'usrp' != OPTS.test:
return return
if OPTS.launch != 'syncref' and OPTS.user == '': if OPTS.launch != 'syncref' and OPTS.user == '':
LOGGER.error("--user followed by [user id] is mandatory to connect to remote machine") LOGGER.error("--user followed by [user id] is mandatory to connect to remote machine")
...@@ -180,69 +193,173 @@ class Command: ...@@ -180,69 +193,173 @@ class Command:
""" """
Scan the provided commands file. Scan the provided commands file.
""" """
self.launch_cmds: Dict[str, str] = {} if OPTS.test.lower() == 'usrp':
if OPTS.test.lower() == 'usrp_b210': launch_cmds_re = re.compile(r'^\s*(\S*)_usrp_\S+_(\S*)_cmd\s*=\s*((\S+\s*)*)')
launch_cmds_re = re.compile(r'^\s*(\S*)usrp_b210\S*\s*=\s*((\S+\s*)*)')
elif OPTS.test.lower() == 'usrp_n310':
launch_cmds_re = re.compile(r'^\s*(\S*)usrp_n310\S*\s*=\s*((\S+\s*)*)')
elif OPTS.test.lower() == 'rfsim': elif OPTS.test.lower() == 'rfsim':
launch_cmds_re = re.compile(r'^\s*(\S*)rfsim\S*\s*=\s*((\S+\s*)*)') launch_cmds_re = re.compile(r'^\s*(\S*)_rfsim_(\S*)_cmd\s*=\s*((\S+\s*)*)')
elif OPTS.test.lower() == 'psbchsim': elif OPTS.test.lower() == 'psbchsim':
launch_cmds_re = re.compile(r'^\s*(\S*)psbchsim\S*\s*=\s*((\S+\s*)*)') launch_cmds_re = re.compile(r'^\s*(\S*)_psbchsim_(\S*)_cmd\s*=\s*((\S+\s*)*)')
elif OPTS.test.lower() == 'psschsim': elif OPTS.test.lower() == 'psschsim':
launch_cmds_re = re.compile(r'^\s*(\S*)psschsim\S*\s*=\s*((\S+\s*)*)') launch_cmds_re = re.compile(r'^\s*(\S*)_psschsim_(\S*)_cmd\s*=\s*((\S+\s*)*)')
else: else:
LOGGER.error("Provided test option not valid! %s", OPTS.test) LOGGER.error("Provided test option not valid! %s", OPTS.test)
sys.exit(1) sys.exit(1)
nearby_host_re = re.compile(r'^\s*(\S*)_usrp_\S*_(\S*)_hostIP\s*=\s*((\S+\s*)*)')
self.launch_cmds = defaultdict(list)
self.hosts = defaultdict(list)
with open(self.filename, 'rt') as in_fh: with open(self.filename, 'rt') as in_fh:
nearby_cmd_continued = False nearby_cmd_continued = False
syncref_cmd_continued = False syncref_cmd_continued = False
target_netid = f'net{OPTS.net}'
for line in in_fh: for line in in_fh:
if line == '\n': if line == '\n':
continue continue
match = launch_cmds_re.match(line) match = launch_cmds_re.match(line)
if match: if match:
host_role = match.group(1) host_role = match.group(1)
launch_cmds = match.group(2) netid = match.group(2)
if host_role.lower().startswith('nearby'): matched_cmd = match.group(3)
match = match and (netid == target_netid)
if match:
if host_role.lower() == 'nearby':
nearby_cmd_continued = True nearby_cmd_continued = True
continue continue
if host_role.lower().startswith('syncref'): if host_role.lower() == 'syncref':
syncref_cmd_continued = True syncref_cmd_continued = True
continue continue
elif nearby_cmd_continued: elif nearby_cmd_continued:
launch_cmds += line matched_cmd += line
if not line.strip().endswith('\\'): if not line.strip().endswith('\\'):
self.launch_cmds['nearby'] = launch_cmds self.launch_cmds['nearby'].append(matched_cmd)
LOGGER.debug('Nearby cmd is %s', launch_cmds) LOGGER.debug('Nearby cmd is %s', matched_cmd)
nearby_cmd_continued = False nearby_cmd_continued = False
continue continue
elif syncref_cmd_continued: elif syncref_cmd_continued:
launch_cmds += line matched_cmd += line
if not line.strip().endswith('\\'): if not line.strip().endswith('\\'):
self.launch_cmds['syncref'] = launch_cmds self.launch_cmds['syncref'].append(matched_cmd)
LOGGER.debug('Syncref cmd is %s', launch_cmds) LOGGER.debug('Syncref cmd is %s', matched_cmd)
syncref_cmd_continued = False syncref_cmd_continued = False
continue continue
else: else:
LOGGER.debug('Unmatched line %r', line) host_match = nearby_host_re.match(line)
continue if host_match:
host_role = host_match.group(1)
netid = host_match.group(2)
matched_host_ip = host_match.group(3)
if host_role.lower() == 'nearby' and netid == target_netid:
self.hosts['nearby'].append(matched_host_ip.strip())
LOGGER.debug('Nearby host is %s\n', matched_host_ip.strip())
continue
else:
LOGGER.debug('Unmatched line %r', line)
continue
if not self.launch_cmds: if not self.launch_cmds:
LOGGER.error('usrp commands are not found in file: %s', self.filename) LOGGER.error('usrp commands are not found in file: %s', self.filename)
sys.exit(1) sys.exit(1)
if OPTS.test.lower() == 'usrp' and not self.hosts['nearby']:
LOGGER.error(f'Nearby host IP is expected. Add nearby host IP to {OPTS.commands}')
sys.exit(1)
class Node:
def __init__(self, id: str, role: str, host: str, cmd:str):
self.id = id # Assumption: UE node id starts from 1.
self.role = role
self.host = host
self.delay = self._get_delay(OPTS.test)
self.log_file_path = os.path.join(OPTS.log_dir, f'{role}{id}.log')
syncref_node_id = '1' if id != '' else '' # str(int(id) - 1)
syncref_node_role = 'syncref' # if id in ('', '1', '2') else 'nearby' # Used for multi hop case.
self.syncref_log_file_path = os.path.join(OPTS.log_dir, f'{syncref_node_role}{syncref_node_id}.log')
self.cmd = self._update_cmd(role, cmd)
self.passed_metric = []
self.num_tx_ssb = []
self.num_passed = 0
self.total_rx_list = []
self.nb_decoded_list = []
self.pssch_rsrp_list = []
self.ssb_rsrp_list = []
self.sync_duration_list = []
def __str__(self):
return f'{self.role}{self.id}'
def _get_delay(self, test_type: str) -> int:
"""
Adjusting launching time by setting delay.
"""
if test_type == 'usrp':
return 5 if self.role == 'syncref' else (1 if self.id in ('', '1', '2') else 0)
else:
return 0 if self.role == 'syncref' else (2 if self.id in ('', '1', '2') else 7)
def _update_cmd(self, role:str, cmd:str) -> str:
if OPTS.basic: return redirect_output('uname -a', self.log_file_path)
dest = '' if '--dest' in cmd or OPTS.dest == '' else f' --dest {OPTS.dest}'
tx_msg = f' --message "{OPTS.message}"' if len(OPTS.message) > 0 else ''
if role == 'syncref':
cmd = cmd[:-1] + tx_msg + f' --mcs {OPTS.mcs}' + dest
if 'rfsim' == OPTS.test:
cmd += f' --snr {OPTS.snr}'
if role == 'nearby':
if 'usrp' == OPTS.test:
cmd = cmd[:-2] + tx_msg + f' --mcs {OPTS.mcs}' + cmd[-2] # cmd[-2] is ' (end of cmd)
cmd = cmd + f' -d {OPTS.duration} --nid1 {OPTS.nid1} --nid2 {OPTS.nid2}'
else:
cmd = cmd[:-1] + tx_msg + f' --mcs {OPTS.mcs}'
if 'rfsim' == OPTS.test:
cmd += f' --snr {OPTS.snr}'
return cmd
def get_metric(self, log_agent: LogChecker, itrn_inx: int) -> None:
if self.num_passed != len(self.passed_metric):
# Examine the logs to determine if the test passed
(pssch_rsrp, ssb_rsrp, nb_decoded, total_rx, sync_duration) = self.passed_metric[-1]
num_ssb = log_agent.analyze_syncref_logs(sync_duration, self.syncref_log_file_path)
self.num_tx_ssb += [num_ssb]
self.total_rx_list += [total_rx]
self.sync_duration_list += [sync_duration]
self.nb_decoded_list += [nb_decoded]
self.pssch_rsrp_list += [pssch_rsrp]
self.ssb_rsrp_list += [ssb_rsrp]
LOGGER.info(f"Trial {itrn_inx + 1}/{OPTS.repeat} SYNCHED. {num_ssb} SSB(s) were generated. Measured {ssb_rsrp} RSRP (dbm/RE)")
else:
LOGGER.info(f"No metric available due to sync failure in {itrn_inx + 1}/{OPTS.repeat} trial(s).")
self.num_passed = len(self.passed_metric)
def show_metric(self) -> None:
LOGGER.info('-' * 42)
atten_snr = {"rfsim": f'SNR value {OPTS.snr}', "usrp": f'Attenuation value {OPTS.att}'}
LOGGER.info(f"{atten_snr[OPTS.test]}, MCS value {OPTS.mcs}")
LOGGER.info(f"Number of synced = {len(self.passed_metric)}/{OPTS.repeat}")
if len(self.num_tx_ssb) > 0:
LOGGER.info(f"Avg number of SSB = {sum(self.num_tx_ssb) / len(self.num_tx_ssb)} ({self.num_tx_ssb})")
if len(self.passed_metric) > 0:
sum_nb_decoded, sum_total_rx = sum(self.nb_decoded_list), sum(self.total_rx_list)
avg_bler = (float) (sum_total_rx - sum_nb_decoded) / sum_total_rx if sum_total_rx > 0 else 1
avg_bldr = (float) (sum_nb_decoded) / sum_total_rx if sum_total_rx > 0 else 1
LOGGER.info(f"Avg PSSCH RSRP = {sum(self.pssch_rsrp_list) / len(self.passed_metric):.2f}")
LOGGER.info(f"Avg SSB RSRP = {sum(self.ssb_rsrp_list) / len(self.passed_metric):.2f}")
if sum_total_rx > 0:
LOGGER.info(f"Avg BLER = {avg_bler:.9f} with {sum_total_rx - sum_nb_decoded} / {sum_total_rx}")
LOGGER.info(f"Avg BLDecodedRate = {avg_bldr:.9f} with {sum_nb_decoded} / {sum_total_rx}")
LOGGER.info(f"Avg Sync duration (seconds) = {sum(self.sync_duration_list) / len(self.passed_metric):.2f}")
LOGGER.info(f"pssch_rsrp_list = {self.pssch_rsrp_list}")
LOGGER.info(f"ssb_rsrp_list = {self.ssb_rsrp_list}")
LOGGER.info(f"nb_decoded_list = {self.nb_decoded_list}")
LOGGER.info(f"total_rx_list = {self.total_rx_list}")
LOGGER.info('#' * 42)
class TestThread(threading.Thread): class TestThread(threading.Thread):
""" """
Represents TestThread Represents TestThread
""" """
def __init__(self, queue, commands, passed, log_agent): def __init__(self, queue, log_agent):
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.queue = queue self.queue = queue
self.commands = commands
self.passed = passed
self.delay = 0 self.delay = 0
self.log_file = log_agent.txlog_file_path
self.log_agent = log_agent self.log_agent = log_agent
def run(self): def run(self):
...@@ -252,73 +369,64 @@ class TestThread(threading.Thread): ...@@ -252,73 +369,64 @@ class TestThread(threading.Thread):
try: try:
while not self.queue.empty(): while not self.queue.empty():
job = self.queue.get() job = self.queue.get()
if "nearby" == job: if "nearby" == job.role and not OPTS.no_run:
thread_delay(delay = 5) thread_delay(self.delay + job.delay)
self.launch_nearby(job) if 'usrp' == OPTS.test:
if "syncref" == job and not OPTS.no_run: self.launch_nearby_usrp(job)
thread_delay(delay = self.delay) elif 'rfsim' == OPTS.test:
self.launch_nearby_rfsim(job)
if "syncref" == job.role and not OPTS.no_run:
thread_delay(self.delay + job.delay)
self.launch_syncref(job) self.launch_syncref(job)
self.queue.task_done() self.queue.task_done()
except Exception as inst: except Exception as inst:
LOGGER.info(f"Failed to operate on job with type {type(inst)} and args {inst.args}") LOGGER.info(f"Failed to operate on job with type {type(inst)} and args {inst.args}")
def launch_syncref(self, job) -> Popen: def launch_syncref(self, job: Node) -> Popen:
LOGGER.info('Launching SyncRef UE') LOGGER.info(f'Launching SyncRef UE {job}')
if OPTS.basic: cmd = redirect_output('uname -a', self.log_file) proc = Popen(job.cmd, shell=True)
else: cmd = self.commands.launch_cmds[job]
cmd = cmd[:-1] + f' --message {OPTS.message}' + f' --mcs {OPTS.mcs}'
if 'rfsim' in OPTS.test:
cmd += f' --snr {OPTS.snr}'
proc = Popen(cmd, shell=True)
LOGGER.info(f"syncref_proc = {proc}") LOGGER.info(f"syncref_proc = {proc}")
if not OPTS.basic and not OPTS.no_run: if not OPTS.basic and not OPTS.no_run:
LOGGER.info("Process running... %s", job) LOGGER.info(f"Process running... {job}")
time.sleep(OPTS.duration + 10) time.sleep(OPTS.duration + 10)
self.kill_process("syncref", proc) self.kill_process(job, proc)
def launch_nearby(self, job, host=OPTS.host, user=OPTS.user) -> Popen: def launch_nearby_usrp(self, job: Node) -> Popen:
LOGGER.info('Launching Nearby UE') LOGGER.info(f'Launching Nearby UE {job}')
if OPTS.basic: cmd = redirect_output('uname -a', self.log_file) proc = Popen(["ssh", f"{OPTS.user}@{job.host}", job.cmd],
else: cmd = self.commands.launch_cmds[job] shell=False,
if 'usrp' in OPTS.test: stdout=subprocess.PIPE,
cmd = cmd[:-2] + f' --mcs {OPTS.mcs}' + cmd[-2] # cmd[-2] is ' (end of cmd) stderr=subprocess.PIPE)
cmd = cmd + f' -d {OPTS.duration} --nid1 {OPTS.nid1} --nid2 {OPTS.nid2}' LOGGER.info(f"nearby_proc = {proc}")
proc = Popen(["ssh", f"{user}@{host}", cmd], remote_output = proc.stdout.readlines()
shell=False, if remote_output == []:
stdout=subprocess.PIPE, nearby_result = proc.stderr.readlines()
stderr=subprocess.PIPE)
LOGGER.info(f"nearby_proc = {proc}")
remote_output = proc.stdout.readlines()
if remote_output == []:
nearby_result = proc.stderr.readlines()
else:
nearby_result = remote_output
self.kill_process("nearby", proc)
if nearby_result:
self.find_nearby_result_metric(nearby_result)
else: else:
if 'rfsim' in OPTS.test: nearby_result = remote_output
cmd = cmd[:-1] + f' --mcs {OPTS.mcs}' + f' --snr {OPTS.snr}' self.kill_process(job, proc)
else: if nearby_result:
cmd = cmd[:-1] + f' --mcs {OPTS.mcs}' self.find_nearby_result_metric(job, nearby_result)
proc = Popen(cmd, shell=True)
LOGGER.info(f"nearby_proc = {proc}") def launch_nearby_rfsim(self, job: Node) -> Popen:
if not OPTS.basic and not OPTS.no_run: LOGGER.info(f'Launching Nearby UE {job}')
LOGGER.info(f"Process running... {job}") proc = Popen(job.cmd, shell=True)
time.sleep(OPTS.duration) LOGGER.info(f"nearby_proc = {proc}")
self.kill_process("nearby", proc) if not OPTS.basic and not OPTS.no_run:
if proc: LOGGER.info(f"Process running... {job}")
time.sleep(5) time.sleep(OPTS.duration)
nearby_result, user_msg = self.log_agent.analyze_nearby_logs(OPTS.nid1, OPTS.nid2, OPTS.sci2) self.kill_process(job, proc)
if nearby_result: if proc:
self.find_nearby_result_metric([nearby_result]) time.sleep(5)
nearby_result, user_msg = self.log_agent.analyze_nearby_logs(OPTS.nid1, OPTS.nid2, OPTS.sci2, job.log_file_path)
def find_nearby_result_metric(self, remote_log): if nearby_result:
self.find_nearby_result_metric(job, [nearby_result])
def find_nearby_result_metric(self, job: Node, remote_log) -> None:
result_metric = None result_metric = None
for line in remote_log: for line in remote_log:
if type(line) is not str: if type(line) is not str:
line = line.decode() line = line.decode()
if 'usrp' in OPTS.test: if 'usrp' == OPTS.test:
LOGGER.info(line.strip()) LOGGER.info(line.strip())
# 'SyncRef UE found. PSSCH-RSRP: -102 dBm/RE SSS-RSRP: -100 dBm/RE passed 99 total 100 It took {delta_time_s} seconds' # 'SyncRef UE found. PSSCH-RSRP: -102 dBm/RE SSS-RSRP: -100 dBm/RE passed 99 total 100 It took {delta_time_s} seconds'
if 'SyncRef UE found' in line: if 'SyncRef UE found' in line:
...@@ -329,19 +437,26 @@ class TestThread(threading.Thread): ...@@ -329,19 +437,26 @@ class TestThread(threading.Thread):
nb_decoded = int(fields[-7]) nb_decoded = int(fields[-7])
total_rx = int(fields[-5]) total_rx = int(fields[-5])
sync_duration = float(fields[-2]) sync_duration = float(fields[-2])
counting_duration = sync_duration - self.delay result_metric = (pssch_rsrp, ssb_rsrp, nb_decoded, total_rx, sync_duration)
result_metric = (pssch_rsrp, ssb_rsrp, nb_decoded, total_rx, sync_duration, counting_duration) job.passed_metric += [result_metric]
self.passed += [result_metric]
return return
def kill_process(self, job: str, proc: Popen) -> None: def kill_process(self, job: Node, proc: Popen) -> None:
# Wait for the processes to end # Wait for the processes to end
LOGGER.info(f'kill main simulation processes... {job}') passed = True
cmd = ['sudo', 'killall']
cmd.append('-KILL')
if proc: if proc:
status = proc.poll()
if status is None:
LOGGER.info('process is still running, which is good')
else:
passed = False
LOGGER.info(f'{job} process ended early: {status}')
if proc and passed:
LOGGER.info(f'kill main simulation processes... {job}')
cmd = ['sudo', 'killall']
cmd.append('-KILL')
cmd.append('nr-uesoftmodem') cmd.append('nr-uesoftmodem')
if "syncref" == job: if "syncref" == job.role:
subprocess.run(cmd) subprocess.run(cmd)
LOGGER.info(f'Waiting for PID proc.pid for {job}') LOGGER.info(f'Waiting for PID proc.pid for {job}')
proc.kill() proc.kill()
...@@ -350,20 +465,44 @@ class TestThread(threading.Thread): ...@@ -350,20 +465,44 @@ class TestThread(threading.Thread):
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
def set_attenuation(attenuation, atten_host, user) -> Popen: def set_attenuation(attenuation: int, atten_host: str, user: str) -> None:
"""
Attenuation value will be updated only if non-negative is specified by user.
"""
if OPTS.att >= 0: if OPTS.att >= 0:
LOGGER.info('Setting attenuation') LOGGER.info('Setting attenuation')
atten_cmd = f"curl http://169.254.10.10/:CHAN:3:SETATT:{attenuation}" atten_set_cmd = f"curl http://169.254.10.10/:CHAN:3:SETATT:{attenuation}" #CHAN:1:2:3:4:SETATT:25.5
LOCAL_IP = check_output(['hostname', '-I']).decode().strip().split()[0] atten_get_cmd = f"curl http://169.254.10.10/:ATT?"
cmd = [atten_cmd] if atten_host == LOCAL_IP else ["ssh", f"{user}@{atten_host}", atten_cmd] host_IPs = check_output(['hostname', '-I']).decode().strip().split()
shell_flag = True if atten_host == LOCAL_IP else False LOCAL_IP = host_IPs[1] if len(host_IPs) > 1 else host_IPs[0]
Popen(cmd, atten_cmds = [atten_set_cmd, atten_get_cmd]
shell=shell_flag, cmd = shlex.split('; '.join(atten_cmds)) if atten_host == LOCAL_IP else ["ssh", f"{user}@{atten_host}"] + atten_cmds
stdout=subprocess.PIPE, proc = Popen(cmd,
stderr=subprocess.PIPE) shell=False,
LOGGER.info(f"attenuation value = {attenuation}") text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out = proc.communicate(timeout=5)[0].strip().split('\n')[-1]
LOGGER.info(f"attenuation value {attenuation} among: {out}")
time.sleep(1) time.sleep(1)
def generate_jobs(commands: Command) -> list:
jobs, node_id, host = [], '', OPTS.host
if commands.launch_cmds is not None:
for role, cmd_list in commands.launch_cmds.items():
for cmd in cmd_list:
if 'node-number' in cmd:
node_id = cmd.split('node-number', 1)[-1].split(maxsplit=1)[0]
if role == 'nearby' and OPTS.host == '':
host = commands.hosts[role].pop(0)
if OPTS.launch == 'all':
jobs.append(Node(node_id, role, host, cmd))
elif role == OPTS.launch:
jobs.append(Node(node_id, role, host, cmd))
LOGGER.debug(f'{role}{node_id} UE IP : {host}')
LOGGER.debug(f'{role}{node_id} UE cmd: {cmd}')
if OPTS.test == 'usrp': jobs.reverse()
return jobs
def main() -> int: def main() -> int:
""" """
...@@ -372,19 +511,8 @@ def main() -> int: ...@@ -372,19 +511,8 @@ def main() -> int:
commands = Command(OPTS.commands) commands = Command(OPTS.commands)
log_agent = LogChecker(OPTS, LOGGER) log_agent = LogChecker(OPTS, LOGGER)
LOGGER.debug(f'Number of iterations {OPTS.repeat}') LOGGER.debug(f'Number of iterations {OPTS.repeat}')
if commands.launch_cmds is not None: jobs = generate_jobs(commands)
for role, cmd in commands.launch_cmds.items(): if 'usrp' == OPTS.test:
LOGGER.debug(f'{role} UE: {cmd}')
jobs = ['nearby', 'syncref'] if OPTS.launch == 'both' else [OPTS.launch]
passed_metric = []
num_tx_ssb = []
num_passed = 0
total_rx_list = []
nb_decoded_list = []
pssch_rsrp_list = []
ssb_rsrp_list = []
sync_duration_list = []
if 'usrp' in OPTS.test:
set_attenuation(OPTS.att, OPTS.att_host, OPTS.att_user) set_attenuation(OPTS.att, OPTS.att_host, OPTS.att_user)
for i in range(OPTS.repeat): for i in range(OPTS.repeat):
LOGGER.info('-' * 42) LOGGER.info('-' * 42)
...@@ -392,48 +520,15 @@ def main() -> int: ...@@ -392,48 +520,15 @@ def main() -> int:
queue = Queue() queue = Queue()
for job in jobs: for job in jobs:
queue.put(job) queue.put(job)
th = TestThread(queue, commands, passed_metric, log_agent) th = TestThread(queue, log_agent)
th.setDaemon(True) th.setDaemon(True)
th.start() th.start()
threads.append(th) threads.append(th)
for th in threads: for th in threads:
th.join() th.join()
if 'nearby' in jobs: for job in [job for job in jobs if job.role == 'nearby']:
if num_passed != len(passed_metric): job.get_metric(log_agent, i)
# Examine the logs to determine if the test passed job.show_metric()
(pssch_rsrp, ssb_rsrp, nb_decoded, total_rx, sync_duration, counting_duration) = passed_metric[-1]
num_ssb = log_agent.analyze_syncref_logs(counting_duration)
num_tx_ssb += [num_ssb]
total_rx_list += [total_rx]
sync_duration_list += [sync_duration]
nb_decoded_list += [nb_decoded]
pssch_rsrp_list += [pssch_rsrp]
ssb_rsrp_list += [ssb_rsrp]
LOGGER.info(f"Trial {i+1}/{OPTS.repeat} SYNCHED. {num_ssb} SSB(s) were generated. Measured {ssb_rsrp} RSRP (dbm/RE)")
else:
LOGGER.info(f"Failure detected during {i+1}/{OPTS.repeat} trial(s).")
num_passed = len(passed_metric)
LOGGER.info('#' * 42)
atten_snr = {"rfsim": f'SNR value {OPTS.snr}', "usrp_": f'Attenuation value {OPTS.att}'}
LOGGER.info(f"{atten_snr[OPTS.test[:5]]}, MCS value {OPTS.mcs}")
if 'nearby' in jobs:
LOGGER.info(f"Number of synced = {len(passed_metric)}/{OPTS.repeat}")
if len(num_tx_ssb) > 0:
LOGGER.info(f"Avg number of SSB = {sum(num_tx_ssb) / len(num_tx_ssb)} ({num_tx_ssb})")
if len(passed_metric) > 0:
sum_nb_decoded, sum_total_rx = sum(nb_decoded_list), sum(total_rx_list)
avg_bler = (float) (sum_total_rx - sum_nb_decoded) / sum_total_rx if sum_total_rx > 0 else 1
avg_bldr = (float) (sum_nb_decoded) / sum_total_rx if sum_total_rx > 0 else 1
LOGGER.info(f"Avg PSSCH RSRP = {sum(pssch_rsrp_list) / len(passed_metric):.2f}")
LOGGER.info(f"Avg SSB RSRP = {sum(ssb_rsrp_list) / len(passed_metric):.2f}")
LOGGER.info(f"Avg BLER = {avg_bler:.9f} with {sum_total_rx - sum_nb_decoded} / {sum_total_rx}")
LOGGER.info(f"Avg BLDecodedRate = {avg_bldr:.9f} with {sum_nb_decoded} / {sum_total_rx}")
LOGGER.info(f"Avg Sync duration (seconds) = {sum(sync_duration_list) / len(passed_metric):.2f}")
LOGGER.info(f"pssch_rsrp_list = {pssch_rsrp_list}")
LOGGER.info(f"ssb_rsrp_list = {ssb_rsrp_list}")
LOGGER.info(f"nb_decoded_list = {nb_decoded_list}")
LOGGER.info(f"total_rx_list = {total_rx_list}")
LOGGER.info('-' * 42)
time.sleep(10) time.sleep(10)
return 0 return 0
......
...@@ -8,8 +8,6 @@ class LogChecker(): ...@@ -8,8 +8,6 @@ class LogChecker():
def __init__(self, OPTS, LOGGER): def __init__(self, OPTS, LOGGER):
self.OPTS = OPTS self.OPTS = OPTS
self.LOGGER = LOGGER self.LOGGER = LOGGER
self.rxlog_file_path = os.path.join(OPTS.log_dir, 'rx.log')
self.txlog_file_path = os.path.join(OPTS.log_dir, 'tx.log')
def get_lines(self, filename: str) -> Generator[str, None, None]: def get_lines(self, filename: str) -> Generator[str, None, None]:
""" """
...@@ -29,7 +27,7 @@ class LogChecker(): ...@@ -29,7 +27,7 @@ class LogChecker():
for line in self.get_lines(filename): for line in self.get_lines(filename):
yield line yield line
def analyze_nearby_logs(self, exp_nid1: int, exp_nid2: int, sci2: bool) -> bool: def analyze_nearby_logs(self, exp_nid1: int, exp_nid2: int, sci2: bool, log_file: str) -> bool:
""" """
Checking matched sync logs of Nearby UE. Checking matched sync logs of Nearby UE.
""" """
...@@ -38,7 +36,6 @@ class LogChecker(): ...@@ -38,7 +36,6 @@ class LogChecker():
ssb_rsrp = 0 ssb_rsrp = 0
nb_decoded = 0 nb_decoded = 0
total_rx = 0 total_rx = 0
log_file = self.rxlog_file_path
result = None result = None
user_msg = None user_msg = None
...@@ -55,7 +52,7 @@ class LogChecker(): ...@@ -55,7 +52,7 @@ class LogChecker():
est_nid2 = int(fields[10]) est_nid2 = int(fields[10])
if 'RSRP' in line: if 'RSRP' in line:
ssb_rsrp = int(fields[12]) ssb_rsrp = int(fields[12])
found.add('found') found.add('syncref')
time_end_s = float(fields[0]) time_end_s = float(fields[0])
#153092.995494 [NR_PHY] In nr_ue_sl_pssch_rsrp_measurements: [UE 0] adj_ue_index 0 PSSCH-RSRP: -63 dBm/RE (6685627) #153092.995494 [NR_PHY] In nr_ue_sl_pssch_rsrp_measurements: [UE 0] adj_ue_index 0 PSSCH-RSRP: -63 dBm/RE (6685627)
...@@ -77,7 +74,7 @@ class LogChecker(): ...@@ -77,7 +74,7 @@ class LogChecker():
if 'the polar decoder output is:' in line: if 'the polar decoder output is:' in line:
line = line.strip() line = line.strip()
user_msg = line user_msg = line
found.add('found') found.add('sci2')
else: else:
if 'Received your text! It says:' in line: if 'Received your text! It says:' in line:
line = line.strip() line = line.strip()
...@@ -85,20 +82,21 @@ class LogChecker(): ...@@ -85,20 +82,21 @@ class LogChecker():
found.add('found') found.add('found')
self.LOGGER.debug('found: %r', found) self.LOGGER.debug('found: %r', found)
if len(found) != 1: if 'syncref' not in found:
self.LOGGER.error(f'Failed -- No SyncRef UE found.') self.LOGGER.error(f'Failed -- No SyncRef UE.')
return return (result, user_msg)
if exp_nid1 != est_nid1 or exp_nid2 != est_nid2: if exp_nid1 != est_nid1 or exp_nid2 != est_nid2:
self.LOGGER.error(f'Failed -- found SyncRef UE Nid1 {est_nid1}, Ni2 {est_nid2}, expecting Nid1 {exp_nid1}, Nid2 {exp_nid2}') self.LOGGER.error(f'Failed -- found SyncRef UE Nid1 {est_nid1}, Ni2 {est_nid2}, expecting Nid1 {exp_nid1}, Nid2 {exp_nid2}')
return return (result, user_msg)
if time_start_s == -1: if time_start_s == -1:
self.LOGGER.error(f'Failed -- No start time found! Fix log and re-run!') self.LOGGER.error(f'Failed -- No start time found! Fix log and re-run!')
return return (result, user_msg)
delta_time_s = time_end_s - time_start_s delta_time_s = time_end_s - time_start_s
result = f'SyncRef UE found. PSSCH-RSRP: {pssch_rsrp} dBm/RE. SSS-RSRP: {ssb_rsrp} dBm/RE passed {nb_decoded} total {total_rx} It took {delta_time_s} seconds' result = f'SyncRef UE found. PSSCH-RSRP: {pssch_rsrp} dBm/RE. SSS-RSRP: {ssb_rsrp} dBm/RE passed {nb_decoded} total {total_rx} It took {delta_time_s} seconds'
self.LOGGER.info(result) self.LOGGER.info(result)
self.LOGGER.info(user_msg) if user_msg != None:
self.LOGGER.info(user_msg)
return (result, user_msg) return (result, user_msg)
def get_analysis_messages_syncref(self, filename: str) -> Generator[str, None, None]: def get_analysis_messages_syncref(self, filename: str) -> Generator[str, None, None]:
...@@ -113,23 +111,21 @@ class LogChecker(): ...@@ -113,23 +111,21 @@ class LogChecker():
if len(fields) == 4 or len(fields) == 6 : if len(fields) == 4 or len(fields) == 6 :
yield line yield line
def analyze_syncref_logs(self, counting_delta: float) -> int: def analyze_syncref_logs(self, sync_duration: float, log_file: str) -> int:
""" """
Checking logs of SyncRef UE. Checking logs of SyncRef UE.
""" """
time_start_s, time_end_s = -1, -1 time_start_s, time_end_s = -1, -1
log_file = self.txlog_file_path
sum_ssb = 0 sum_ssb = 0
if self.OPTS.compress: if self.OPTS.compress:
log_file = f'{log_file}.bz2' log_file = f'{log_file}.bz2'
for line in self.get_analysis_messages_syncref(log_file): for line in self.get_analysis_messages_syncref(log_file):
#796811.532881 [NR_PHY] nrUE configured
#796821.854505 [NR_PHY] PSBCH SL generation started #796821.854505 [NR_PHY] PSBCH SL generation started
if time_start_s == -1 and 'nrUE configured' in line: if time_start_s == -1 and 'PSBCH SL generation started' in line:
fields = line.split(maxsplit=2) fields = line.split(maxsplit=2)
time_start_s = float(fields[0]) time_start_s = float(fields[0])
time_end_s = time_start_s + counting_delta time_end_s = time_start_s + sync_duration
if 'PSBCH SL generation started' in line: if 'PSBCH SL generation started' in line:
fields = line.split(maxsplit=2) fields = line.split(maxsplit=2)
time_st = float(''.join([ch for ch in fields[0] if ch.isnumeric() or ch =='.'])) time_st = float(''.join([ch for ch in fields[0] if ch.isnumeric() or ch =='.']))
......
# The lines containing 'usrp' and starts with 'syncref' or 'nearby' will be valid until it does not contain backspace. # The lines containing 'usrp' and starts with 'syncref' or 'nearby' will be valid until it does not contain backspace.
######################### ################################################################
#### USRP B210 #### #### USRP B210 --- USRP B210 ####
######################### ################################################################
### TX SyncRef UE ###
syncref_usrp_b210_net0_cmd = \
sudo -E LD_LIBRARY_PATH=$HOME/openairinterface5g/cmake_targets/ran_build/build:$LD_LIBRARY_PATH \
$HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \
--sl-mode 2 --sync-ref --rbsl 52 --numerology 1 --band 38 --SLC 2600000000 --ue-txgain 0 \
--usrp-args "type=b200,serial=3150384,clock_source=external" \
--log_config.global_log_options time,nocolor \
> ~/syncref.log 2>&1
### RX Nearby UE ### ### RX Nearby UE ###
nearby_usrp_b210_cmd = cd $HOME/openairinterface5g/ci-scripts; \ nearby_usrp_b210_net0_hostIP = 10.1.1.61
nearby_usrp_b210_net0_cmd = cd $HOME/openairinterface5g/ci-scripts; \
python3 sl_rx_agent.py --cmd \ python3 sl_rx_agent.py --cmd \
'sudo -E LD_LIBRARY_PATH=$HOME/openairinterface5g/cmake_targets/ran_build/build:$LD_LIBRARY_PATH \ 'sudo -E LD_LIBRARY_PATH=$HOME/openairinterface5g/cmake_targets/ran_build/build:$LD_LIBRARY_PATH \
$HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \ $HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \
--sl-mode 2 --rbsl 52 --numerology 1 --band 38 --SLC 2600000000 --ue-rxgain 90 \ --sl-mode 2 --rbsl 52 --numerology 1 --band 38 --SLC 2600000000 --ue-rxgain 90 \
--usrp-args "type=b200,serial=3150361,clock_source=external" \ --usrp-args "type=b200,serial=3150361,clock_source=external" \
--log_config.global_log_options time,nocolor \ --log_config.global_log_options time,nocolor \
> ~/rx.log 2>&1' > ~/nearby.log 2>&1'
################################################################
#### USRP N310 --- USRP N310 ####
################################################################
### TX SyncRef UE ### ### TX SyncRef UE ###
syncref_usrp_b210_cmd = \ syncref_usrp_n310_net1_cmd = \
sudo -E LD_LIBRARY_PATH=$HOME/openairinterface5g/cmake_targets/ran_build/build:$LD_LIBRARY_PATH \ sudo -E LD_LIBRARY_PATH=$HOME/openairinterface5g/cmake_targets/ran_build/build:$LD_LIBRARY_PATH \
$HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \ $HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \
--sl-mode 2 --sync-ref --rbsl 52 --numerology 1 --band 38 --SLC 2600000000 --ue-txgain 0 \ --sl-mode 2 --sync-ref --rbsl 52 --numerology 1 --band 78 --SLC 3600000000 --ue-txgain 0 \
--usrp-args "type=b200,serial=3150384,clock_source=external" \ --usrp-args "type=n3xx,addr=192.168.10.2,subdev=A:0,master_clock_rate=122.88e6" \
--log_config.global_log_options time,nocolor \ --log_config.global_log_options time,nocolor \
> ~/tx.log 2>&1 > ~/syncref.log 2>&1
#########################
#### USRP N310 ####
#########################
### RX Nearby UE ### ### RX Nearby UE ###
nearby_usrp_n310_cmd = cd $HOME/openairinterface5g/ci-scripts; \ nearby_usrp_n310_net1_hostIP = 10.1.1.80
nearby_usrp_n310_net1_cmd = cd $HOME/openairinterface5g/ci-scripts; \
python3 sl_rx_agent.py --cmd \ python3 sl_rx_agent.py --cmd \
'sudo -E LD_LIBRARY_PATH=$HOME/openairinterface5g/cmake_targets/ran_build/build:$LD_LIBRARY_PATH \ 'sudo -E LD_LIBRARY_PATH=$HOME/openairinterface5g/cmake_targets/ran_build/build:$LD_LIBRARY_PATH \
$HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \ $HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \
--sl-mode 2 --rbsl 52 --numerology 1 --band 38 --SLC 2600000000 --ue-rxgain 20 \ --sl-mode 2 --rbsl 52 --numerology 1 --band 78 --SLC 3600000000 --ue-rxgain 75 \
--usrp-args "type=n3xx,addr=192.168.20.2,subdev=A:0,master_clock_rate=122.88e6" \ --usrp-args "type=n3xx,addr=192.168.10.2,subdev=A:0,master_clock_rate=122.88e6" \
--log_config.global_log_options time,nocolor \ --log_config.global_log_options time,nocolor \
> ~/rx.log 2>&1' > ~/nearby.log 2>&1'
################################################################
#### Multi-hop: USRP N310 --- USRP N310 --- USRP B210 ####
################################################################
### TX SyncRef UE ### ### TX SyncRef UE ###
syncref_usrp_n310_cmd = \ syncref_usrp_n310_net2_cmd = \
sudo -E LD_LIBRARY_PATH=$HOME/openairinterface5g/cmake_targets/ran_build/build:$LD_LIBRARY_PATH \ sudo -E LD_LIBRARY_PATH=$HOME/openairinterface5g/cmake_targets/ran_build/build:$LD_LIBRARY_PATH \
$HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \ $HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \
--sl-mode 2 --sync-ref --rbsl 52 --numerology 1 --band 38 --SLC 2600000000 --ue-txgain 0 \ --sl-mode 2 --sync-ref --rbsl 52 --numerology 1 --band 78 --SLC 3600000000 --ue-txgain 0 \
--usrp-args "type=n3xx,addr=192.168.10.2,subdev=A:0,master_clock_rate=122.88e6" \ --usrp-args "type=n3xx,addr=192.168.10.2,subdev=A:0,master_clock_rate=122.88e6" \
--log_config.global_log_options time,nocolor \ --log_config.global_log_options time,nocolor --node-number 1 \
> ~/tx.log 2>&1 > ~/syncref1.log 2>&1
### Relay UE ###
nearby_usrp_n310_net2_hostIP = 10.1.1.80
nearby_usrp_n310_net2_cmd = cd $HOME/openairinterface5g/ci-scripts; \
python3 sl_rx_agent.py --cmd \
'sudo -E LD_LIBRARY_PATH=$HOME/openairinterface5g/cmake_targets/ran_build/build:$LD_LIBRARY_PATH \
$HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \
--sl-mode 2 --rbsl 52 --numerology 1 --band 78 --SLC 3600000000 --ue-txgain 0 --ue-rxgain 75 \
--usrp-args "type=n3xx,addr=192.168.10.2,subdev=A:0,master_clock_rate=122.88e6" \
--log_config.global_log_options time,nocolor --node-number 2 \
> ~/nearby2.log 2>&1'
######################### ### RX Nearby UE ###
#### RFSIMULATOR #### nearby_usrp_b210_net2_hostIP = 10.1.1.63
######################### nearby_usrp_b210_net2_cmd = cd $HOME/openairinterface5g/ci-scripts; \
python3 sl_rx_agent.py --cmd \
'sudo -E LD_LIBRARY_PATH=$HOME/openairinterface5g/cmake_targets/ran_build/build:$LD_LIBRARY_PATH \
$HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \
--sl-mode 2 --rbsl 52 --numerology 1 --band 78 --SLC 3600000000 --ue-rxgain 100 \
--usrp-args "type=b200,serial=3150384,clock_source=external" \
--log_config.global_log_options time,nocolor --node-number 3 \
> ~/nearby3.log 2>&1'
################################################################
#### RFSIMULATOR : SyncRef UE --- Nearby UE ####
################################################################
### TX SyncRef UE ###
syncref_rfsim_net1_cmd = \
sudo -E RFSIMULATOR=server \
$HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \
--sync-ref --rfsim --sl-mode 2 --rbsl 106 --SLC 3300000000 --ue-txgain 0 \
--rfsimulator.serverport 4048 --log_config.global_log_options time,nocolor \
> ~/syncref.log 2>&1
### RX Nearby UE ### ### RX Nearby UE ###
nearby_rfsim_cmd = \ nearby_rfsim_net1_cmd = \
sudo -E RFSIMULATOR=127.0.0.1 \ sudo -E RFSIMULATOR=127.0.0.1 \
$HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \ $HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \
--rfsim --sl-mode 2 --rbsl 106 --SLC 3300000000 --ue-rxgain 20 --rfsimulator.serverport 4048 \ --rfsim --sl-mode 2 --rbsl 106 --SLC 3300000000 --ue-rxgain 90 \
--log_config.global_log_options time,nocolor \ --rfsimulator.serverport 4048 --log_config.global_log_options time,nocolor \
> ~/rx.log 2>&1 > ~/nearby.log 2>&1
################################################################
#### RFSIMULATOR : SyncRef UE --- Relay UE --- Nearby UE ####
################################################################
### TX SyncRef UE ### ### TX SyncRef UE ###
syncref_rfsim_cmd = \ syncref_rfsim_net2_cmd = \
sudo -E RFSIMULATOR=127.0.0.1 \
$HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \
--sync-ref --rfsim --sl-mode 2 --rbsl 52 --SLC 2600000000 --ue-txgain 0 --node-number 1 \
--rfsimulator.serverport 4048 --log_config.global_log_options time,nocolor \
> ~/syncref1.log 2>&1
### Relay UE ###
nearby_rfsim_net2_cmd = \
sudo -E RFSIMULATOR=server \ sudo -E RFSIMULATOR=server \
$HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \ $HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \
--sync-ref --rfsim --sl-mode 2 --rbsl 106 --SLC 3300000000 --ue-txgain 0 --rfsimulator.serverport 4048 \ --rfsim --sl-mode 2 --rbsl 52 --SLC 2600000000 --ue-txgain 0 --ue-rxgain 90 --node-number 2 \
--log_config.global_log_options time,nocolor \ --rfsimulator.serverport 4048 --log_config.global_log_options time,nocolor \
> ~/tx.log 2>&1 > ~/nearby2.log 2>&1
### RX Nearby UE ###
nearby_rfsim_net2_cmd = \
sudo -E RFSIMULATOR=127.0.0.1 \
$HOME/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \
--rfsim --sl-mode 2 --rbsl 52 --SLC 2600000000 --ue-rxgain 90 --node-number 3 \
--rfsimulator.serverport 4048 --log_config.global_log_options time,nocolor \
> ~/nearby3.log 2>&1
...@@ -46,28 +46,32 @@ parser = argparse.ArgumentParser(description=""" ...@@ -46,28 +46,32 @@ parser = argparse.ArgumentParser(description="""
Automated tests for 5G NR Sidelink Rx simulations Automated tests for 5G NR Sidelink Rx simulations
""") """)
parser.add_argument('--duration', '-d', metavar='SECONDS', type=int, default=20, help=""" parser.add_argument('--compress', '-c', action='store_true', help="""
How long to run the test before stopping to examine the logs Compress the log files in the --log-dir
""") """)
parser.add_argument('--cmd', type=str, default=DEFAULT_USRP_CMD, help=""" parser.add_argument('--cmd', type=str, default=DEFAULT_USRP_CMD, help="""
Commands Commands
""") """)
parser.add_argument('--nid1', type=int, default=10, help=""" parser.add_argument('--debug', action='store_true', help="""
Nid1 value Enable debug logging (for this script only)
""") """)
parser.add_argument('--nid2', type=int, default=1, help=""" parser.add_argument('--duration', '-d', metavar='SECONDS', type=int, default=20, help="""
Nid2 value How long to run the test before stopping to examine the logs
""") """)
parser.add_argument('--log-dir', default=HOME_DIR, help=""" parser.add_argument('--log-dir', default=HOME_DIR, help="""
Where to store log files Where to store log files
""") """)
parser.add_argument('--compress', '-c', action='store_true', help=""" parser.add_argument('--nid1', type=int, default=10, help="""
Compress the log files in the --log-dir Nid1 value
""")
parser.add_argument('--nid2', type=int, default=1, help="""
Nid2 value
""") """)
parser.add_argument('--no-run', '-n', action='store_true', help=""" parser.add_argument('--no-run', '-n', action='store_true', help="""
...@@ -75,10 +79,6 @@ Don't run the test, only examine the logs in the --log-dir ...@@ -75,10 +79,6 @@ Don't run the test, only examine the logs in the --log-dir
directory from a previous run of the test directory from a previous run of the test
""") """)
parser.add_argument('--debug', action='store_true', help="""
Enable debug logging (for this script only)
""")
parser.add_argument('--sci2', action='store_true', help=""" parser.add_argument('--sci2', action='store_true', help="""
Enable SCI2 log parsing (this will grep the logs for the SCI2 payload) Enable SCI2 log parsing (this will grep the logs for the SCI2 payload)
""") """)
...@@ -90,8 +90,6 @@ logging.basicConfig(level=logging.DEBUG if OPTS.debug else logging.INFO, ...@@ -90,8 +90,6 @@ logging.basicConfig(level=logging.DEBUG if OPTS.debug else logging.INFO,
format='>>> %(name)s: %(levelname)s: %(message)s') format='>>> %(name)s: %(levelname)s: %(message)s')
LOGGER = logging.getLogger(os.path.basename(sys.argv[0])) LOGGER = logging.getLogger(os.path.basename(sys.argv[0]))
log_file_path = os.path.join(OPTS.log_dir, 'rx.log')
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
def compress(from_name: str, to_name: Optional[str]=None, remove_original: bool=False) -> None: def compress(from_name: str, to_name: Optional[str]=None, remove_original: bool=False) -> None:
...@@ -159,69 +157,79 @@ class TestNearby(): ...@@ -159,69 +157,79 @@ class TestNearby():
""" """
Represents TestNearby Represents TestNearby
""" """
def __init__(self): def __init__(self, cmd: str):
self.cmd = None self.cmd = cmd
self.delay = 0 # seconds self.delay = 0 # seconds
self.id = self._get_id(cmd)
self.role = "nearby"
self.log_file_path = os.path.join(OPTS.log_dir, f'{self.role}{self.id}.log')
def run(self, cmd: str) -> bool: def __str__(self) -> str:
self.cmd = cmd return f'{self.role}{self.id}'
job = "nearby"
def _get_id(self) -> str:
node_id = ''
if 'node-number' in self.cmd:
node_id = self.cmd.split('node-number')[-1].split()[0]
return node_id
def run(self) -> bool:
time.sleep(self.delay) time.sleep(self.delay)
proc = self.launch_nearby(job) proc = self.launch_nearby()
LOGGER.info(f"nearby_proc = {proc}") LOGGER.info(f"nearby_proc = {proc}")
LOGGER.info(f"Process running... {job}") LOGGER.info(f"Process running... {self}")
time.sleep(OPTS.duration) time.sleep(OPTS.duration)
passed = self.kill_process("nearby", proc) passed = self.kill_process(proc)
if OPTS.compress: if OPTS.compress:
self.compress_log_file(proc) self.compress_log_file(proc)
return passed return passed
def launch_nearby(self, job) -> Popen: def launch_nearby(self) -> Popen:
LOGGER.info('Launching Nearby UE: %s', log_file_path) LOGGER.info('Launching Nearby UE')
cmd = self.cmd proc = Popen(self.cmd, shell=True)
proc = Popen(cmd, shell=True)
time.sleep(1) time.sleep(1)
return proc return proc
def kill_process(self, job: str, proc: Popen) -> bool: def kill_process(self, proc: Popen) -> bool:
passed = True passed = True
if proc: if proc:
status = proc.poll() status = proc.poll()
if status is None: if status is None:
LOGGER.info('process is still running, which is good') LOGGER.info('process is still running, which is good')
else: else:
#passed = False passed = False
LOGGER.info('process ended early: %r', status) LOGGER.info('process ended early: %r', status)
LOGGER.info(f'kill main simulation processes... {job}') LOGGER.info(f'{self} process ended early: {status}')
cmd = ['sudo', 'killall'] if proc and passed:
cmd.append('-KILL') LOGGER.info(f'kill main simulation processes... {self}')
if proc: cmd = ['sudo', 'killall']
cmd.append('-KILL')
cmd.append('nr-uesoftmodem') cmd.append('nr-uesoftmodem')
if "nearby" == job: if "nearby" == self.role:
subprocess.run(cmd) subprocess.run(cmd)
LOGGER.info(f'Waiting for PID proc.pid for {job}') LOGGER.info(f'Waiting for PID proc.pid for {self}')
proc.kill() proc.kill()
proc.wait() proc.wait()
LOGGER.info(f'kill main simulation processes...done for {job}') LOGGER.info(f'kill main simulation processes...done for {self}')
return passed return passed
def compress_log_file(self, proc: Popen): def compress_log_file(self, proc: Popen):
jobs = CompressJobs() jobs = CompressJobs()
jobs.compress(log_file_path) jobs.compress(self.log_file_path)
jobs.wait() jobs.wait()
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
def main(argv) -> int: def main(argv) -> int:
test_agent = TestNearby() test_agent = TestNearby(OPTS.cmd)
log_agent = LogChecker(OPTS, LOGGER) log_agent = LogChecker(OPTS, LOGGER)
passed = True passed = True
if not OPTS.no_run: if not OPTS.no_run:
passed = test_agent.run(OPTS.cmd) passed = test_agent.run()
# Examine the logs to determine if the test passed # Examine the logs to determine if the test passed
result, user_msg = log_agent.analyze_nearby_logs(exp_nid1=OPTS.nid1, exp_nid2=OPTS.nid2, sci2=OPTS.sci2) result, user_msg = log_agent.analyze_nearby_logs(OPTS.nid1, OPTS.nid2, OPTS.sci2, test_agent.log_file_path)
if not result or not user_msg: if not result or not user_msg:
passed = False passed = False
......
...@@ -138,6 +138,7 @@ extern "C" ...@@ -138,6 +138,7 @@ extern "C"
#define NFAPI softmodem_params.nfapi #define NFAPI softmodem_params.nfapi
#define NSA softmodem_params.nsa #define NSA softmodem_params.nsa
#define NODE_NUMBER softmodem_params.node_number #define NODE_NUMBER softmodem_params.node_number
#define SL_DEST_ID softmodem_params.dest_id
#define NON_STOP softmodem_params.non_stop #define NON_STOP softmodem_params.non_stop
#define EMULATE_L1 softmodem_params.emulate_l1 #define EMULATE_L1 softmodem_params.emulate_l1
#define CONTINUOUS_TX softmodem_params.continuous_tx #define CONTINUOUS_TX softmodem_params.continuous_tx
...@@ -182,6 +183,7 @@ extern int usrp_tx_thread; ...@@ -182,6 +183,7 @@ extern int usrp_tx_thread;
{"chest-time", CONFIG_HLP_CHESTTIME, 0, iptr:&CHEST_TIME, defintval:0, TYPE_INT, 0}, \ {"chest-time", CONFIG_HLP_CHESTTIME, 0, iptr:&CHEST_TIME, defintval:0, TYPE_INT, 0}, \
{"nsa", CONFIG_HLP_NSA, PARAMFLAG_BOOL, iptr:&NSA, defintval:0, TYPE_INT, 0}, \ {"nsa", CONFIG_HLP_NSA, PARAMFLAG_BOOL, iptr:&NSA, defintval:0, TYPE_INT, 0}, \
{"node-number", NULL, 0, u16ptr:&NODE_NUMBER, defuintval:0, TYPE_UINT16, 0}, \ {"node-number", NULL, 0, u16ptr:&NODE_NUMBER, defuintval:0, TYPE_UINT16, 0}, \
{"dest", NULL, 0, u16ptr:&SL_DEST_ID, defuintval:0, TYPE_UINT16, 0}, \
{"usrp-tx-thread-config", CONFIG_HLP_USRP_THREAD, 0, iptr:&usrp_tx_thread, defstrval:0, TYPE_INT, 0}, \ {"usrp-tx-thread-config", CONFIG_HLP_USRP_THREAD, 0, iptr:&usrp_tx_thread, defstrval:0, TYPE_INT, 0}, \
{"nfapi", CONFIG_HLP_NFAPI, 0, u8ptr:&nfapi_mode, defintval:0, TYPE_UINT8, 0}, \ {"nfapi", CONFIG_HLP_NFAPI, 0, u8ptr:&nfapi_mode, defintval:0, TYPE_UINT8, 0}, \
{"non-stop", CONFIG_HLP_NONSTOP, PARAMFLAG_BOOL, iptr:&NON_STOP, defintval:0, TYPE_INT, 0}, \ {"non-stop", CONFIG_HLP_NONSTOP, PARAMFLAG_BOOL, iptr:&NON_STOP, defintval:0, TYPE_INT, 0}, \
...@@ -191,7 +193,7 @@ extern int usrp_tx_thread; ...@@ -191,7 +193,7 @@ extern int usrp_tx_thread;
{"sync-ref", CONFIG_HLP_SYNC_REF, PARAMFLAG_BOOL, iptr:&SYNC_REF, defintval:0, TYPE_INT, 0}, \ {"sync-ref", CONFIG_HLP_SYNC_REF, PARAMFLAG_BOOL, iptr:&SYNC_REF, defintval:0, TYPE_INT, 0}, \
{"nid1", CONFIG_HLP_NID1, 0, iptr:&NID1, defintval:10, TYPE_INT, 0}, \ {"nid1", CONFIG_HLP_NID1, 0, iptr:&NID1, defintval:10, TYPE_INT, 0}, \
{"nid2", CONFIG_HLP_NID2, 0, iptr:&NID2, defintval:1, TYPE_INT, 0}, \ {"nid2", CONFIG_HLP_NID2, 0, iptr:&NID2, defintval:1, TYPE_INT, 0}, \
{"message", CONFIG_HLP_MSG, 0, strptr:&SL_USER_MSG, defstrval:"EpiScience",TYPE_STRING, 0}, \ {"message", CONFIG_HLP_MSG, 0, strptr:&SL_USER_MSG, defstrval:NULL, TYPE_STRING, 0}, \
} }
#define CONFIG_HLP_NSA "Enable NSA mode \n" #define CONFIG_HLP_NSA "Enable NSA mode \n"
...@@ -287,6 +289,7 @@ typedef struct { ...@@ -287,6 +289,7 @@ typedef struct {
uint8_t nfapi; uint8_t nfapi;
int nsa; int nsa;
uint16_t node_number; uint16_t node_number;
uint16_t dest_id;
int non_stop; int non_stop;
int emulate_l1; int emulate_l1;
int continuous_tx; int continuous_tx;
......
...@@ -330,8 +330,7 @@ int nr_sl_initial_sync(UE_nr_rxtx_proc_t *proc, ...@@ -330,8 +330,7 @@ int nr_sl_initial_sync(UE_nr_rxtx_proc_t *proc,
if (ret == 0) { if (ret == 0) {
nr_gold_psbch(ue); nr_gold_psbch(ue);
ret = nr_psbch_detection(proc, ue, 0, &phy_pdcch_config); ret = nr_psbch_detection(proc, ue, 0, &phy_pdcch_config);
if ((ret == 0) && (proc->nr_slot_rx != ue->slss->sl_timeoffsetssb_r16) && (get_softmodem_params()->node_number)) {
if ((proc->nr_slot_rx != ue->slss->sl_timeoffsetssb_r16) && (get_softmodem_params()->node_number)) {
LOG_I(PHY, "Filtering out the direct connection between SyncRef UE and Nearby UE when Relay UE exists.\n"); LOG_I(PHY, "Filtering out the direct connection between SyncRef UE and Nearby UE when Relay UE exists.\n");
return -1; return -1;
} }
......
...@@ -206,16 +206,7 @@ void nr_pssch_data_control_multiplexing(uint8_t *in_slssh, ...@@ -206,16 +206,7 @@ void nr_pssch_data_control_multiplexing(uint8_t *in_slssh,
uint32_t get_B_multiplexed_value(NR_DL_FRAME_PARMS* fp, NR_DL_UE_HARQ_t *harq) { uint32_t get_B_multiplexed_value(NR_DL_FRAME_PARMS* fp, NR_DL_UE_HARQ_t *harq) {
uint8_t number_of_symbols = harq->nb_symbols ;
uint16_t nb_rb = harq->nb_rb;
uint8_t Nl = harq->Nl; uint8_t Nl = harq->Nl;
uint8_t mod_order = harq->Qm ;
uint16_t dmrs_pos = harq->dlDmrsSymbPos ;
uint16_t length_dmrs = get_num_dmrs(dmrs_pos);
uint8_t nb_dmrs_re_per_rb = 6 * harq->n_dmrs_cdm_groups;
unsigned int G_slsch_bits = harq->G; unsigned int G_slsch_bits = harq->G;
uint32_t B_mul = G_slsch_bits + harq->B_sci2 * Nl; uint32_t B_mul = G_slsch_bits + harq->B_sci2 * Nl;
return B_mul; return B_mul;
...@@ -280,7 +271,7 @@ void nr_ue_set_slsch_rx(PHY_VARS_NR_UE *ue, unsigned char harq_pid) ...@@ -280,7 +271,7 @@ void nr_ue_set_slsch_rx(PHY_VARS_NR_UE *ue, unsigned char harq_pid)
unsigned int TBS = nr_compute_tbs_sl(mod_order, code_rate, nb_rb, nb_re_sci1, nb_re_sci2, nb_symb_sch, nb_re_dmrs * length_dmrs, 0, 0, Nl); unsigned int TBS = nr_compute_tbs_sl(mod_order, code_rate, nb_rb, nb_re_sci1, nb_re_sci2, nb_symb_sch, nb_re_dmrs * length_dmrs, 0, 0, Nl);
harq->TBS = TBS >> 3; harq->TBS = TBS >> 3;
harq->G = nr_get_G_sl(nb_rb, nb_re_sci1, nb_re_sci2, harq->nb_symbols, nb_re_dmrs, length_dmrs, harq->Qm, harq->Nl); harq->G = nr_get_G_sl(nb_rb, nb_re_sci1, nb_re_sci2, harq->nb_symbols, nb_re_dmrs, length_dmrs, harq->Qm, harq->Nl);
LOG_I(NR_PHY, "mcs %u polar_encoder_output_len %u, code_rate %d, TBS %d\n", Imcs, harq->B_sci2, code_rate, TBS); LOG_D(NR_PHY, "mcs %u polar_encoder_output_len %u, code_rate %d, TBS %d\n", Imcs, harq->B_sci2, code_rate, TBS);
harq->status = ACTIVE; harq->status = ACTIVE;
nfapi_nr_pssch_pdu_t *rel16_sl_rx = &harq->pssch_pdu; nfapi_nr_pssch_pdu_t *rel16_sl_rx = &harq->pssch_pdu;
...@@ -309,7 +300,6 @@ void nr_ue_set_slsch(NR_DL_FRAME_PARMS *fp, ...@@ -309,7 +300,6 @@ void nr_ue_set_slsch(NR_DL_FRAME_PARMS *fp,
uint8_t slot) { uint8_t slot) {
NR_UL_UE_HARQ_t *harq = slsch->harq_processes[harq_pid]; NR_UL_UE_HARQ_t *harq = slsch->harq_processes[harq_pid];
uint8_t nb_codewords = 1; uint8_t nb_codewords = 1;
uint8_t N_PRB_oh = 0;
uint16_t nb_symb_sch = 12; uint16_t nb_symb_sch = 12;
uint16_t nb_symb_cch = 3; // Assumption there are three SLCCH symbols uint16_t nb_symb_cch = 3; // Assumption there are three SLCCH symbols
int nb_rb = get_PRB(fp->N_RB_SL); int nb_rb = get_PRB(fp->N_RB_SL);
...@@ -330,7 +320,6 @@ void nr_ue_set_slsch(NR_DL_FRAME_PARMS *fp, ...@@ -330,7 +320,6 @@ void nr_ue_set_slsch(NR_DL_FRAME_PARMS *fp,
uint8_t length_dmrs = get_num_dmrs(dmrsSymbPos); uint8_t length_dmrs = get_num_dmrs(dmrsSymbPos);
uint16_t code_rate = nr_get_code_rate_ul(Imcs, 0); uint16_t code_rate = nr_get_code_rate_ul(Imcs, 0);
uint8_t mod_order = nr_get_Qm_ul(Imcs, 0); uint8_t mod_order = nr_get_Qm_ul(Imcs, 0);
uint16_t nb_symb_psfch = 0;
harq->pssch_pdu.mcs_index = Imcs; harq->pssch_pdu.mcs_index = Imcs;
harq->pssch_pdu.nrOfLayers = Nl; harq->pssch_pdu.nrOfLayers = Nl;
harq->pssch_pdu.rb_size = nb_rb; harq->pssch_pdu.rb_size = nb_rb;
...@@ -354,7 +343,6 @@ void nr_ue_set_slsch(NR_DL_FRAME_PARMS *fp, ...@@ -354,7 +343,6 @@ void nr_ue_set_slsch(NR_DL_FRAME_PARMS *fp,
nb_re_dmrs = 4 * harq->pssch_pdu.num_dmrs_cdm_grps_no_data; nb_re_dmrs = 4 * harq->pssch_pdu.num_dmrs_cdm_grps_no_data;
} }
uint16_t N_RE_prime = NR_NB_SC_PER_RB * (nb_symb_sch - nb_symb_psfch) - nb_re_dmrs - N_PRB_oh;
uint16_t nb_re_sci1 = nb_symb_cch * NB_RB_SCI1 * NR_NB_SC_PER_RB; uint16_t nb_re_sci1 = nb_symb_cch * NB_RB_SCI1 * NR_NB_SC_PER_RB;
uint16_t polar_encoder_output_len = polar_encoder_output_length(code_rate, harq->num_of_mod_symbols); uint16_t polar_encoder_output_len = polar_encoder_output_length(code_rate, harq->num_of_mod_symbols);
uint8_t SCI2_mod_order = 2; uint8_t SCI2_mod_order = 2;
...@@ -369,31 +357,34 @@ void nr_ue_set_slsch(NR_DL_FRAME_PARMS *fp, ...@@ -369,31 +357,34 @@ void nr_ue_set_slsch(NR_DL_FRAME_PARMS *fp,
unsigned char *test_input = harq->a; unsigned char *test_input = harq->a;
uint64_t *sci_input = harq->a_sci2; uint64_t *sci_input = harq->a_sci2;
bool payload_type_string = false; char *sl_user_msg = get_softmodem_params()->sl_user_msg;
uint32_t sl_user_msg_len = (sl_user_msg != NULL) ? strlen(sl_user_msg) : 0;
bool payload_type_string = (sl_user_msg_len > 0) ? true : false;
if(qsize_of_relay_data() == 0) { if(qsize_of_relay_data() == 0) {
if (payload_type_string) { if (payload_type_string) {
for (int i = 0; i < 32; i++) { memcpy(test_input, sl_user_msg, sl_user_msg_len);
test_input[i] = get_softmodem_params()->sl_user_msg[i]; LOG_D(NR_PHY, "SLSCH_TX will send %s\n", test_input);
}
} else { } else {
srand(time(NULL)); srand(time(NULL));
for (int i = 0; i < TBS / 8; i++) for (int i = 0; i < min(32, TBS / 8); i++)
test_input[i] = (unsigned char) (i+3);//rand(); test_input[i] = '0' + (unsigned char) (i + 3) % 10;//rand();
test_input[0] = (unsigned char) (slot); // test_input[0] = (unsigned char) (slot);
test_input[1] = (unsigned char) (frame & 0xFF); // 8 bits LSB // test_input[1] = (unsigned char) (frame & 0xFF); // 8 bits LSB
test_input[2] = (unsigned char) ((frame >> 8) & 0x3); // // test_input[2] = (unsigned char) ((frame >> 8) & 0x3); //
test_input[3] = (unsigned char) ((frame & 0x111) << 5) + (unsigned char) (slot) + rand() % 256; // test_input[3] = (unsigned char) ((frame & 0x111) << 5) + (unsigned char) (slot) + rand() % 256;
LOG_D(NR_PHY, "SLSCH_TX will send %u\n", test_input[3]); LOG_D(NR_PHY, "SLSCH_TX will send %u\n", test_input[3]);
} }
uint64_t u = 0; uint64_t u = 0;
uint64_t dest = 0; uint64_t dest_id = (0x2 + ((slot % 2) == 0 ? 1 : 0)) * get_softmodem_params()->node_number;
dest = (0x2 + ((slot % 2) == 0 ? 1 : 0)) * get_softmodem_params()->node_number; dest_id = (0x2 + ((slot % 2) == 0 ? 1 : 0)) * get_softmodem_params()->node_number;
u ^= (dest << 32); if (get_softmodem_params()->dest_id > 0)
dest_id = get_softmodem_params()->dest_id;
u ^= (dest_id << 32);
*sci_input = u; *sci_input = u;
} else { } else {
get_relay_data_from_buffer(test_input, sci_input, TBS / 8); get_relay_data_from_buffer(test_input, sci_input, TBS / 8);
uint64_t dest = (*sci_input >> 32) & 0xFFFF; uint64_t dest = (*sci_input >> 32) & 0xFFFF;
LOG_W(NR_PHY, "SLSCH_TX will forward with original slot index %u for dest %d\n", test_input[0], dest); LOG_W(NR_PHY, "SLSCH_TX will forward with original slot index %u for dest %lu\n", test_input[0], dest);
} }
} }
...@@ -404,7 +395,6 @@ void nr_ue_slsch_tx_procedures(PHY_VARS_NR_UE *txUE, ...@@ -404,7 +395,6 @@ void nr_ue_slsch_tx_procedures(PHY_VARS_NR_UE *txUE,
LOG_D(NR_PHY, "nr_ue_slsch_tx_procedures hard_id %d %d.%d\n", harq_pid, frame, slot); LOG_D(NR_PHY, "nr_ue_slsch_tx_procedures hard_id %d %d.%d\n", harq_pid, frame, slot);
uint8_t nb_dmrs_re_per_rb;
NR_DL_FRAME_PARMS *frame_parms = &txUE->frame_parms; NR_DL_FRAME_PARMS *frame_parms = &txUE->frame_parms;
int32_t **txdataF = txUE->common_vars.txdataF; int32_t **txdataF = txUE->common_vars.txdataF;
...@@ -416,11 +406,6 @@ void nr_ue_slsch_tx_procedures(PHY_VARS_NR_UE *txUE, ...@@ -416,11 +406,6 @@ void nr_ue_slsch_tx_procedures(PHY_VARS_NR_UE *txUE,
uint16_t nb_rb = pssch_pdu->rb_size; uint16_t nb_rb = pssch_pdu->rb_size;
uint8_t Nl = pssch_pdu->nrOfLayers; uint8_t Nl = pssch_pdu->nrOfLayers;
uint8_t mod_order = pssch_pdu->qam_mod_order; uint8_t mod_order = pssch_pdu->qam_mod_order;
uint8_t cdm_grps_no_data = pssch_pdu->num_dmrs_cdm_grps_no_data;
uint16_t dmrs_pos = pssch_pdu->sl_dmrs_symb_pos;
uint16_t length_dmrs = get_num_dmrs(dmrs_pos);
nb_dmrs_re_per_rb = 6 * cdm_grps_no_data;
/////////////////////////SLSCH data and SCI2 encoding///////////////////////// /////////////////////////SLSCH data and SCI2 encoding/////////////////////////
unsigned int G_slsch_bits = harq_process_ul_ue->G; unsigned int G_slsch_bits = harq_process_ul_ue->G;
...@@ -808,12 +793,10 @@ uint32_t nr_ue_slsch_rx_procedures(PHY_VARS_NR_UE *rxUE, ...@@ -808,12 +793,10 @@ uint32_t nr_ue_slsch_rx_procedures(PHY_VARS_NR_UE *rxUE,
int nb_re_SCI2 = slsch_ue_rx->harq_processes[0]->B_sci2/SCI2_mod_order; int nb_re_SCI2 = slsch_ue_rx->harq_processes[0]->B_sci2/SCI2_mod_order;
uint8_t nb_re_dmrs = 6 * slsch_ue_rx_harq->n_dmrs_cdm_groups; uint8_t nb_re_dmrs = 6 * slsch_ue_rx_harq->n_dmrs_cdm_groups;
uint32_t dmrs_data_re = 12 - nb_re_dmrs; uint32_t dmrs_data_re = 12 - nb_re_dmrs;
uint16_t length_dmrs = get_num_dmrs(dmrs_pos);
unsigned int G = slsch_ue_rx_harq->G; unsigned int G = slsch_ue_rx_harq->G;
uint16_t num_data_symbs = (G << 1) / mod_order; uint16_t num_data_symbs = (G << 1) / mod_order;
uint32_t M_SCI2_bits = slsch_ue_rx->harq_processes[0]->B_sci2 * Nl; uint32_t M_SCI2_bits = slsch_ue_rx->harq_processes[0]->B_sci2 * Nl;
uint16_t num_sci2_symbs = (M_SCI2_bits << 1) / SCI2_mod_order; uint16_t num_sci2_symbs = (M_SCI2_bits << 1) / SCI2_mod_order;
uint16_t num_sci2_samples = num_sci2_symbs >> 1;
int avgs = 0; int avgs = 0;
int avg[16]; int avg[16];
......
...@@ -1468,7 +1468,6 @@ int phy_procedures_nrUE_SL_RX(PHY_VARS_NR_UE *ue, ...@@ -1468,7 +1468,6 @@ int phy_procedures_nrUE_SL_RX(PHY_VARS_NR_UE *ue,
int32_t **rxdataF = ue->common_vars.common_vars_rx_data_per_thread[0].rxdataF; int32_t **rxdataF = ue->common_vars.common_vars_rx_data_per_thread[0].rxdataF;
uint64_t rx_offset = (slot_rx&3)*(ue->frame_parms.symbols_per_slot * ue->frame_parms.ofdm_symbol_size); uint64_t rx_offset = (slot_rx&3)*(ue->frame_parms.symbols_per_slot * ue->frame_parms.ofdm_symbol_size);
bool payload_type_string = false;
static bool detect_new_dest; static bool detect_new_dest;
uint16_t node_id = get_softmodem_params()->node_number; uint16_t node_id = get_softmodem_params()->node_number;
uint32_t B_mul = get_B_multiplexed_value(&ue->frame_parms, slsch->harq_processes[0]); uint32_t B_mul = get_B_multiplexed_value(&ue->frame_parms, slsch->harq_processes[0]);
...@@ -1485,10 +1484,12 @@ int phy_procedures_nrUE_SL_RX(PHY_VARS_NR_UE *ue, ...@@ -1485,10 +1484,12 @@ int phy_procedures_nrUE_SL_RX(PHY_VARS_NR_UE *ue,
} }
uint32_t ret = nr_ue_slsch_rx_procedures(ue, harq_pid, frame_rx, slot_rx, rxdataF, B_mul, Nidx, proc); uint32_t ret = nr_ue_slsch_rx_procedures(ue, harq_pid, frame_rx, slot_rx, rxdataF, B_mul, Nidx, proc);
bool payload_type_string = true;
bool polar_decoded = (ret < LDPC_MAX_LIMIT) ? true : false; bool polar_decoded = (ret < LDPC_MAX_LIMIT) ? true : false;
uint16_t dest = (*harq->b_sci2 >> 32) & 0xFFFF; uint16_t dest = (*harq->b_sci2 >> 32) & 0xFFFF;
bool dest_matched = (dest == node_id); bool dest_matched = (dest == node_id);
LOG_I(PHY, "dest %u vs %u node_id for hex %lx\n", dest, node_id, *harq->b_sci2); if (polar_decoded)
LOG_D(PHY, "dest %u vs %u node_id for hex %lx\n", dest, node_id, *harq->b_sci2);
if ((ret != -1) && dest_matched) { if ((ret != -1) && dest_matched) {
if (payload_type_string) if (payload_type_string)
validate_rx_payload_str(harq, slot_rx, polar_decoded); validate_rx_payload_str(harq, slot_rx, polar_decoded);
...@@ -1513,13 +1514,13 @@ int phy_procedures_nrUE_SL_RX(PHY_VARS_NR_UE *ue, ...@@ -1513,13 +1514,13 @@ int phy_procedures_nrUE_SL_RX(PHY_VARS_NR_UE *ue,
return (0); return (0);
} }
#define DEBUG_NR_PSSCHSIM
void /* The above code is likely defining a function called "validate_rx_payload" in the C programming void /* The above code is likely defining a function called "validate_rx_payload" in the C programming
language. */ language. */
/* The above code is likely a function or method called "validate_rx_payload" written in the C /* The above code is likely a function or method called "validate_rx_payload" written in the C
programming language. However, without the actual code implementation, it is not possible to programming language. However, without the actual code implementation, it is not possible to
determine what the function does. */ determine what the function does. */
validate_rx_payload(NR_DL_UE_HARQ_t *harq, int frame_rx, int slot_rx, bool polar_decoded) { validate_rx_payload(NR_DL_UE_HARQ_t *harq, int frame_rx, int slot_rx, bool polar_decoded) {
#define DEBUG_NR_PSSCHSIM
unsigned int errors_bit = 0; unsigned int errors_bit = 0;
unsigned int n_false_positive = 0; unsigned int n_false_positive = 0;
#ifdef DEBUG_NR_PSSCHSIM #ifdef DEBUG_NR_PSSCHSIM
...@@ -1546,7 +1547,7 @@ validate_rx_payload(NR_DL_UE_HARQ_t *harq, int frame_rx, int slot_rx, bool polar ...@@ -1546,7 +1547,7 @@ validate_rx_payload(NR_DL_UE_HARQ_t *harq, int frame_rx, int slot_rx, bool polar
if (i == 8 * 2) frame_tx += (harq->b[2] << 8); if (i == 8 * 2) frame_tx += (harq->b[2] << 8);
if (i == 8 * 3) randm_tx = harq->b[3]; if (i == 8 * 3) randm_tx = harq->b[3];
if (i >= 8 * comparison_beg_byte) if (i >= 8 * comparison_beg_byte)
LOG_I(PHY,"TxByte : %4u vs %4u : RxByte\n", test_input[i / 8], harq->b[i / 8]); LOG_I(NR_PHY, "TxByte : %4c vs %4c : RxByte\n", test_input[i / 8], harq->b[i / 8]);
} }
LOG_D(NR_PHY, "tx bit: %u, rx bit: %u\n", test_input_bit[i], estimated_output_bit[i]); LOG_D(NR_PHY, "tx bit: %u, rx bit: %u\n", test_input_bit[i], estimated_output_bit[i]);
...@@ -1558,43 +1559,49 @@ validate_rx_payload(NR_DL_UE_HARQ_t *harq, int frame_rx, int slot_rx, bool polar ...@@ -1558,43 +1559,49 @@ validate_rx_payload(NR_DL_UE_HARQ_t *harq, int frame_rx, int slot_rx, bool polar
} }
} }
LOG_I(PHY,"TxRandm: %4u\n", randm_tx); LOG_I(NR_PHY, "TxRandm: %4u\n", randm_tx);
LOG_I(PHY,"TxFrame: %4u vs %4u : RxFrame\n", frame_tx, (uint32_t) frame_rx); LOG_I(NR_PHY, "TxFrame: %4u vs %4u : RxFrame\n", frame_tx, (uint32_t) frame_rx);
LOG_I(PHY,"TxSlot : %4u vs %4u : RxSlot \n", slot_tx, (uint8_t) slot_rx); LOG_I(NR_PHY, "TxSlot : %4u vs %4u : RxSlot \n", slot_tx, (uint8_t) slot_rx);
} }
#endif #endif
if (errors_bit > 0 || polar_decoded == false) { if (errors_bit > 0 || polar_decoded == false) {
n_false_positive++; n_false_positive++;
++sum_failed; ++sum_failed;
LOG_I(PHY,"errors_bit %u, polar_decoded %d\n", errors_bit, polar_decoded); LOG_I(NR_PHY, "errors_bit %u, polar_decoded %d\n", errors_bit, polar_decoded);
LOG_I(PHY, "PSSCH test NG with %d / %d = %4.2f\n", sum_passed, (sum_passed + sum_failed), (float) sum_passed / (float) (sum_passed + sum_failed)); LOG_I(NR_PHY, "PSSCH test NG with %d / %d = %4.2f\n", sum_passed, (sum_passed + sum_failed), (float) sum_passed / (float) (sum_passed + sum_failed));
} else { } else {
++sum_passed; ++sum_passed;
LOG_I(PHY, "PSSCH test OK with %d / %d = %4.2f\n", sum_passed, (sum_passed + sum_failed), (float) sum_passed / (float) (sum_passed + sum_failed)); LOG_I(NR_PHY, "PSSCH test OK with %d / %d = %4.2f\n", sum_passed, (sum_passed + sum_failed), (float) sum_passed / (float) (sum_passed + sum_failed));
// if (slot_rx ==4) // if (slot_rx ==4)
// exit(0); // exit(0);
} }
} }
void validate_rx_payload_str(NR_DL_UE_HARQ_t *harq, int slot, bool polar_decoded) { void validate_rx_payload_str(NR_DL_UE_HARQ_t *harq, int slot, bool polar_decoded) {
#define MAX_MSG_SIZE 128
unsigned int errors_bit = 0; unsigned int errors_bit = 0;
unsigned char estimated_output_bit[HNA_SIZE]; char estimated_output_bit[HNA_SIZE];
unsigned char test_input_bit[HNA_SIZE]; char test_input_bit[HNA_SIZE];
unsigned int n_false_positive = 0; unsigned int n_false_positive = 0;
unsigned char test_input[] = "EpiScience"; char default_input[MAX_MSG_SIZE] = "";
char *sl_user_msg = get_softmodem_params()->sl_user_msg;
char *test_input = (sl_user_msg != NULL) ? sl_user_msg : default_input;
uint32_t default_msg_len = (sl_user_msg != NULL) ? strlen(sl_user_msg) : MAX_MSG_SIZE;
uint32_t test_msg_len = min(max(10, strlen((char *) harq->b)), min(default_msg_len, harq->TBS));
static uint16_t sum_passed = 0; static uint16_t sum_passed = 0;
static uint16_t sum_failed = 0; static uint16_t sum_failed = 0;
uint8_t comparison_end_byte = 10; uint8_t comparison_end_byte = test_msg_len;
if (polar_decoded == true) { if (polar_decoded == true) {
for (int i = 0; i < min(32, harq->TBS) * 8; i++) { //max tx string size is 32 bytes for (int i = 0; i < test_msg_len * 8; i++) { //max tx string size is 32 bytes
estimated_output_bit[i] = (harq->b[i / 8] & (1 << (i & 7))) >> (i & 7); estimated_output_bit[i] = (harq->b[i / 8] & (1 << (i & 7))) >> (i & 7);
test_input_bit[i] = (test_input[i / 8] & (1 << (i & 7))) >> (i & 7); // Further correct for multiple segments test_input_bit[i] = (test_input[i / 8] & (1 << (i & 7))) >> (i & 7); // Further correct for multiple segments
if(i % 8 == 0){ if(i % 8 == 0){
LOG_D(PHY,"TxByte : %c vs %c : RxByte\n", test_input[i / 8], harq->b[i / 8]); LOG_D(NR_PHY, "TxByte : %c vs %c : RxByte\n", test_input[i / 8], harq->b[i / 8]);
} }
#ifdef DEBUG_NR_PSSCHSIM #ifdef DEBUG_NR_PSSCHSIM
LOG_I(NR_PHY, "tx bit: %u, rx bit: %u\n", test_input_bit[i], estimated_output_bit[i]); LOG_D(NR_PHY, "tx bit: %u, rx bit: %u\n", test_input_bit[i], estimated_output_bit[i]);
#endif #endif
if (i >= 8 * comparison_end_byte) if (i >= 8 * comparison_end_byte)
break; break;
...@@ -1602,30 +1609,28 @@ void validate_rx_payload_str(NR_DL_UE_HARQ_t *harq, int slot, bool polar_decoded ...@@ -1602,30 +1609,28 @@ void validate_rx_payload_str(NR_DL_UE_HARQ_t *harq, int slot, bool polar_decoded
errors_bit++; errors_bit++;
} }
} }
}
if (errors_bit > 0 || polar_decoded == false) { static char result[MAX_MSG_SIZE];
static unsigned char result[128]; for (int i = 0; i < test_msg_len; i++) {
for (int i = 0; i < min(128, harq->TBS); i++) {
result[i] = harq->b[i]; result[i] = harq->b[i];
LOG_D(PHY, "result[%d]=%c\n", i, result[i]); LOG_D(NR_PHY, "result[%d]=%c\n", i, result[i]);
} }
unsigned char *usr_msg_ptr = &result[0]; char *usr_msg_ptr = &result[0];
char tmp_flag[128];
memset(tmp_flag, '+', strlen("Received your text! It says: ") + test_msg_len);
LOG_I(NR_PHY, "%s\n", tmp_flag);
LOG_I(NR_PHY, "Received your text! It says: %s\n", usr_msg_ptr); LOG_I(NR_PHY, "Received your text! It says: %s\n", usr_msg_ptr);
LOG_I(PHY, "Decoded_payload for slot %d: %s\n", slot, result); LOG_D(NR_PHY, "Decoded_payload for slot %d: %s\n", slot, result);
LOG_I(NR_PHY, "%s\n", tmp_flag);
}
if (errors_bit > 0 || polar_decoded == false) {
n_false_positive++; n_false_positive++;
++sum_failed; ++sum_failed;
LOG_I(PHY,"errors_bit %u, polar_decoded %d\n", errors_bit, polar_decoded); LOG_I(PHY,"errors_bit %u, polar_decoded %d\n", errors_bit, polar_decoded);
LOG_I(PHY, "PSSCH test NG with %d / %d = %4.2f\n", sum_passed, (sum_passed + sum_failed), (float) sum_passed / (float) (sum_passed + sum_failed)); LOG_I(PHY, "PSSCH test NG with %d / %d = %4.2f\n", sum_passed, (sum_passed + sum_failed), (float) sum_passed / (float) (sum_passed + sum_failed));
} else { } else {
static unsigned char result[128];
for (int i = 0; i < min(128, harq->TBS); i++) {
result[i] = harq->b[i];
LOG_D(PHY, "result[%d]=%c\n", i, result[i]);
}
++sum_passed; ++sum_passed;
unsigned char *usr_msg_ptr = &result[0];
LOG_I(NR_PHY, "Received your text! It says: %s\n", usr_msg_ptr);
LOG_I(PHY, "Decoded_payload for slot %d: %s\n", slot, result);
LOG_I(PHY, "PSSCH test OK with %d / %d = %4.2f\n", sum_passed, (sum_passed + sum_failed), (float) sum_passed / (float) (sum_passed + sum_failed)); LOG_I(PHY, "PSSCH test OK with %d / %d = %4.2f\n", sum_passed, (sum_passed + sum_failed), (float) sum_passed / (float) (sum_passed + sum_failed));
} }
} }
......
...@@ -111,6 +111,7 @@ int loglvl = OAILOG_WARNING; ...@@ -111,6 +111,7 @@ int loglvl = OAILOG_WARNING;
int seed = 0; int seed = 0;
int mcs = 0; int mcs = 0;
uint16_t node_id = 0; uint16_t node_id = 0;
char user_msg[128] = "";
static void get_sim_cl_opts(int argc, char **argv) static void get_sim_cl_opts(int argc, char **argv)
{ {
...@@ -173,6 +174,10 @@ static void get_sim_cl_opts(int argc, char **argv) ...@@ -173,6 +174,10 @@ static void get_sim_cl_opts(int argc, char **argv)
slot = atoi(optarg); slot = atoi(optarg);
break; break;
case 'M':
mcs = atoi(optarg);
break;
case 'm': case 'm':
mu = atoi(optarg); mu = atoi(optarg);
break; break;
...@@ -195,7 +200,7 @@ static void get_sim_cl_opts(int argc, char **argv) ...@@ -195,7 +200,7 @@ static void get_sim_cl_opts(int argc, char **argv)
break; break;
case 't': case 't':
mcs = atoi(optarg); memcpy(user_msg, optarg, strlen(optarg)+1);
break; break;
case 'y': case 'y':
...@@ -216,7 +221,7 @@ static void get_sim_cl_opts(int argc, char **argv) ...@@ -216,7 +221,7 @@ static void get_sim_cl_opts(int argc, char **argv)
default: default:
case 'h': case 'h':
printf("%s -h(elp) -g channel_model -n n_frames -s snr0 -S snr1 -p(extended_prefix) -y TXant -z RXant -M -N cell_id -R -F input_filename -m -l -r\n", argv[0]); printf("%s -h(elp) -g channel_model -n n_frames -s snr0 -S snr1 -p(extended_prefix) -y TXant -z RXant -M MCS -N cell_id -R -F input_filename -m -l -r -t user_message_to_send\n", argv[0]);
//printf("%s -h(elp) -p(extended_prefix) -N cell_id -f output_filename -F input_filename -g channel_model -n n_frames -t Delayspread -s snr0 -S snr1 -x transmission_mode -y TXant -z RXant -i Intefrence0 -j Interference1 -A interpolation_file -C(alibration offset dB) -N CellId\n", argv[0]); //printf("%s -h(elp) -p(extended_prefix) -N cell_id -f output_filename -F input_filename -g channel_model -n n_frames -t Delayspread -s snr0 -S snr1 -x transmission_mode -y TXant -z RXant -i Intefrence0 -j Interference1 -A interpolation_file -C(alibration offset dB) -N CellId\n", argv[0]);
printf("-h This message\n"); printf("-h This message\n");
printf("-g [A,B,C,D,E,F,G] Use 3GPP SCM (A,B,C,D) or 36-101 (E-EPA,F-EVA,G-ETU) models (ignores delay spread and Ricean factor)\n"); printf("-g [A,B,C,D,E,F,G] Use 3GPP SCM (A,B,C,D) or 36-101 (E-EPA,F-EVA,G-ETU) models (ignores delay spread and Ricean factor)\n");
...@@ -229,9 +234,10 @@ static void get_sim_cl_opts(int argc, char **argv) ...@@ -229,9 +234,10 @@ static void get_sim_cl_opts(int argc, char **argv)
printf("-W number of layer\n"); printf("-W number of layer\n");
printf("-r N_RB_SL\n"); printf("-r N_RB_SL\n");
printf("-F Input filename (.txt format) for RX conformance testing\n"); printf("-F Input filename (.txt format) for RX conformance testing\n");
printf("-m MCS\n"); printf("-M MCS\n");
printf("-l number of symbol\n"); printf("-l number of symbol\n");
printf("-r number of RB\n"); printf("-r number of RB\n");
printf("-t User message to send\n");
exit (-1); exit (-1);
break; break;
} }
...@@ -359,7 +365,6 @@ int main(int argc, char **argv) ...@@ -359,7 +365,6 @@ int main(int argc, char **argv)
exit_fun("[NR_PSSCHSIM] Error, configuration module init failed\n"); exit_fun("[NR_PSSCHSIM] Error, configuration module init failed\n");
} }
get_sim_cl_opts(argc, argv); get_sim_cl_opts(argc, argv);
char user_msg[128] = "EpiScience";
get_softmodem_params()->sl_user_msg = user_msg; get_softmodem_params()->sl_user_msg = user_msg;
randominit(0); randominit(0);
// logging initialization // logging initialization
...@@ -450,7 +455,7 @@ int main(int argc, char **argv) ...@@ -450,7 +455,7 @@ int main(int argc, char **argv)
unsigned int n_errors = 0; unsigned int n_errors = 0;
unsigned int n_false_positive = 0; unsigned int n_false_positive = 0;
unsigned int errors_bit_delta = 0; unsigned int errors_bit_delta = 0;
unsigned int num_bytes_to_check = 80; unsigned int num_bytes_to_check = 10;
//double modulated_input[HNA_SIZE]; //double modulated_input[HNA_SIZE];
unsigned char test_input_bit[HNA_SIZE]; unsigned char test_input_bit[HNA_SIZE];
//short channel_output_uncoded[HNA_SIZE]; //short channel_output_uncoded[HNA_SIZE];
...@@ -512,11 +517,14 @@ int main(int argc, char **argv) ...@@ -512,11 +517,14 @@ int main(int argc, char **argv)
txUE->slsch[0][0]->Nidx, txUE->slsch[0][0]->Nidx,
&proc); &proc);
uint32_t rx_msg_len = strlen((char *) harq_process_rxUE->b);
bool payload_type_string = rx_msg_len ? true : false;
num_bytes_to_check = payload_type_string ? min(rx_msg_len, harq_process_rxUE->TBS): min(num_bytes_to_check, harq_process_rxUE->TBS);
bool polar_decoded = (ret < LDPC_MAX_LIMIT) ? true : false; bool polar_decoded = (ret < LDPC_MAX_LIMIT) ? true : false;
if (ret != -1) { if (ret != -1) {
errors_bit_delta = 0; errors_bit_delta = 0;
bool payload_type_string = false; for (int i = 0; i < num_bytes_to_check * 8; i++) {
for (int i = 0; i < num_bytes_to_check; i++) {
estimated_output_bit[i] = (harq_process_rxUE->b[i / 8] & (1 << (i & 7))) >> (i & 7); estimated_output_bit[i] = (harq_process_rxUE->b[i / 8] & (1 << (i & 7))) >> (i & 7);
test_input_bit[i] = (txUE->slsch[0][0]->harq_processes[harq_pid]->a[i / 8] & (1 << (i & 7))) >> (i & 7); // Further correct for multiple segments test_input_bit[i] = (txUE->slsch[0][0]->harq_processes[harq_pid]->a[i / 8] & (1 << (i & 7))) >> (i & 7); // Further correct for multiple segments
#ifdef DEBUG_NR_PSSCHSIM #ifdef DEBUG_NR_PSSCHSIM
...@@ -546,7 +554,7 @@ int main(int argc, char **argv) ...@@ -546,7 +554,7 @@ int main(int argc, char **argv)
printf("*****************************************\n"); printf("*****************************************\n");
printf("SNR %f, BLER %f BER %f\n", SNR, printf("SNR %f, BLER %f BER %f\n", SNR,
(float) n_errors / (float) n_trials, (float) n_errors / (float) n_trials,
(float) errors_bit / (float) (n_trials * num_bytes_to_check)); (float) errors_bit / (float) (n_trials * num_bytes_to_check * 8));
printf("*****************************************\n"); printf("*****************************************\n");
printf("\n"); printf("\n");
......
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