Added relay ping and iperf
This commit is contained in:
parent
6f7f89a068
commit
bac6551797
|
@ -162,6 +162,7 @@ def collect_iperf(
|
||||||
server_ip="10.45.0.1",
|
server_ip="10.45.0.1",
|
||||||
duration=10,
|
duration=10,
|
||||||
is_client=True,
|
is_client=True,
|
||||||
|
stations="",
|
||||||
):
|
):
|
||||||
if is_client:
|
if is_client:
|
||||||
commands = [
|
commands = [
|
||||||
|
@ -233,6 +234,7 @@ def collect_iperf(
|
||||||
"start_distance": start_distance,
|
"start_distance": start_distance,
|
||||||
"location": location,
|
"location": location,
|
||||||
"type": test_type,
|
"type": test_type,
|
||||||
|
"stations": stations,
|
||||||
}
|
}
|
||||||
|
|
||||||
print(f"\n{server_ip} {test_type} IPERF complete")
|
print(f"\n{server_ip} {test_type} IPERF complete")
|
||||||
|
@ -240,6 +242,7 @@ def collect_iperf(
|
||||||
print(f"IPERF receiver bitrate: {receiver_bitrate}")
|
print(f"IPERF receiver bitrate: {receiver_bitrate}")
|
||||||
|
|
||||||
save_data_to_json(data=data, filename=filename)
|
save_data_to_json(data=data, filename=filename)
|
||||||
|
time.sleep(0.25)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"iPerf Error: {e}")
|
print(f"iPerf Error: {e}")
|
||||||
|
@ -269,7 +272,7 @@ def collect_data(filename, address):
|
||||||
# Send to server
|
# Send to server
|
||||||
print(f"\nDistance: {data.get('distance')}")
|
print(f"\nDistance: {data.get('distance')}")
|
||||||
print(f"Service: {data.get('network information')}")
|
print(f"Service: {data.get('network information')}")
|
||||||
print(f"Ping Time: {data.get('ping_time')}")
|
print(f"Ping Time: {data.get(f'{address}_ping_time')}")
|
||||||
print(
|
print(
|
||||||
f"RSRP: {data.get('RSRP PRX')} {data.get('RSRP DRX')} {data.get('RSRP RX2')} {data.get('RSRP RX3')}"
|
f"RSRP: {data.get('RSRP PRX')} {data.get('RSRP DRX')} {data.get('RSRP RX2')} {data.get('RSRP RX3')}"
|
||||||
)
|
)
|
||||||
|
@ -306,12 +309,12 @@ def collect_sierra_data(filename):
|
||||||
def main():
|
def main():
|
||||||
global running
|
global running
|
||||||
address = "10.46.0.1"
|
address = "10.46.0.1"
|
||||||
foldername = "data/boat_relay_sept_18"
|
foldername = "data/office_test_sept_19"
|
||||||
os.makedirs(foldername, exist_ok=True)
|
os.makedirs(foldername, exist_ok=True)
|
||||||
filename = foldername + "/test_" + str(int(time.time())) + ".json"
|
filename = foldername + "/test_" + str(int(time.time())) + ".json"
|
||||||
|
|
||||||
print("Setting configs...")
|
# print("Setting configs...")
|
||||||
set_configs()
|
# set_configs()
|
||||||
|
|
||||||
print(
|
print(
|
||||||
"Type 'l' to set basestation location, 'b' to begin, "
|
"Type 'l' to set basestation location, 'b' to begin, "
|
||||||
|
|
95
end_to_relay_client.py
Normal file
95
end_to_relay_client.py
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
import re
|
||||||
|
import socket
|
||||||
|
|
||||||
|
from helper_functions import normalize, save_data_to_json
|
||||||
|
|
||||||
|
RELAY_IP = "10.45.0.1" # gNodeB IP of relay
|
||||||
|
PORT = 5005
|
||||||
|
BUFFER_SIZE = 4096
|
||||||
|
|
||||||
|
|
||||||
|
def parse_iperf_output(output, test_type):
|
||||||
|
matches = re.findall(
|
||||||
|
r"\[\s*\d+\]\s+\d+\.\d+\-\d+\.\d+\s+sec\s+[\d.]+\s+\w+Bytes\s+([\d.]+)\s+(Kbits/sec|Mbits/sec)",
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(matches) >= 1:
|
||||||
|
# Normalize the last entries
|
||||||
|
last_value, last_unit = matches[-1]
|
||||||
|
sender_bitrate = normalize(float(last_value), last_unit)
|
||||||
|
|
||||||
|
# Try to differentiate sender vs receiver
|
||||||
|
receiver_match = re.search(r"receiver", output, re.IGNORECASE)
|
||||||
|
sender_match = re.search(r"sender", output, re.IGNORECASE)
|
||||||
|
|
||||||
|
if receiver_match and sender_match and len(matches) >= 2:
|
||||||
|
recv_value, recv_unit = matches[-1]
|
||||||
|
send_value, send_unit = matches[-2]
|
||||||
|
receiver_bitrate = normalize(float(recv_value), recv_unit)
|
||||||
|
sender_bitrate = normalize(float(send_value), send_unit)
|
||||||
|
else:
|
||||||
|
receiver_bitrate = sender_bitrate
|
||||||
|
|
||||||
|
else:
|
||||||
|
bitrates = re.findall(r"(\d+\.\d+) Mbits/sec", output)
|
||||||
|
sender_bitrate = float(bitrates[-2])
|
||||||
|
receiver_bitrate = float(bitrates[-1])
|
||||||
|
|
||||||
|
print(f"\nrelay -> ground {test_type} IPERF complete")
|
||||||
|
print(f"IPERF sender bitrate: {sender_bitrate}")
|
||||||
|
print(f"IPERF receiver bitrate: {receiver_bitrate}")
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"iperf_full": output,
|
||||||
|
"sender_bitrate": sender_bitrate,
|
||||||
|
"receiver_bitrate": receiver_bitrate,
|
||||||
|
"type": test_type,
|
||||||
|
"stations": "rg",
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def collect_iperf_remote(filename: str = ""):
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
sock.settimeout(20) # timeout for receiving results
|
||||||
|
|
||||||
|
# Send "start" command
|
||||||
|
sock.sendto(b"start", (RELAY_IP, PORT))
|
||||||
|
print(f"[End] Sent start command to relay {RELAY_IP}:{PORT}")
|
||||||
|
|
||||||
|
# Collect results
|
||||||
|
results = []
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
data, _ = sock.recvfrom(BUFFER_SIZE)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
results.append(data.decode())
|
||||||
|
except socket.timeout:
|
||||||
|
pass
|
||||||
|
|
||||||
|
full_output = "".join(results)
|
||||||
|
|
||||||
|
# Split output into normal vs reverse
|
||||||
|
normal_section = ""
|
||||||
|
reverse_section = ""
|
||||||
|
if "=== Reverse Test" in full_output:
|
||||||
|
parts = full_output.split("=== Reverse Test (Ground → Relay) ===")
|
||||||
|
normal_section = (
|
||||||
|
parts[0].replace("=== Normal Test (Relay → Ground) ===", "").strip()
|
||||||
|
)
|
||||||
|
reverse_section = parts[1].strip() if len(parts) > 1 else ""
|
||||||
|
else:
|
||||||
|
normal_section = full_output.strip()
|
||||||
|
|
||||||
|
uplink_data = parse_iperf_output(output=normal_section, test_type="uplink")
|
||||||
|
downlink_data = parse_iperf_output(output=reverse_section, test_type="downlink")
|
||||||
|
|
||||||
|
if filename:
|
||||||
|
save_data_to_json(data=uplink_data, filename=filename)
|
||||||
|
save_data_to_json(data=downlink_data, filename=filename)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
collect_iperf_remote()
|
213
relay.py
Normal file
213
relay.py
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
from at_commands import (
|
||||||
|
get_modem_cops,
|
||||||
|
get_modem_cpol,
|
||||||
|
get_modem_creg,
|
||||||
|
get_modem_csq,
|
||||||
|
get_modem_qnwcfg,
|
||||||
|
get_modem_qnwinfo,
|
||||||
|
get_modem_qspn,
|
||||||
|
get_modem_rsrp,
|
||||||
|
get_modem_rsrq,
|
||||||
|
get_modem_sinr,
|
||||||
|
set_configs,
|
||||||
|
)
|
||||||
|
from communication import (
|
||||||
|
collect_iperf,
|
||||||
|
get_current_location,
|
||||||
|
ping_basestation,
|
||||||
|
set_base_location,
|
||||||
|
)
|
||||||
|
from end_to_relay_client import collect_iperf_remote
|
||||||
|
from helper_functions import save_data_to_json
|
||||||
|
|
||||||
|
# Globals
|
||||||
|
running = False # To control start/stop
|
||||||
|
|
||||||
|
|
||||||
|
# Ping base station
|
||||||
|
def ping_basestation(address="10.45.0.1", name="10.45.0.1", dictionary={}) -> dict:
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
["ping", "-c", "1", address], capture_output=True, text=True
|
||||||
|
)
|
||||||
|
match = re.search(r"time=([\d.]+)", result.stdout)
|
||||||
|
|
||||||
|
if match:
|
||||||
|
time_value = match.group(1)
|
||||||
|
dictionary[f"{name}_ping_time"] = time_value
|
||||||
|
else:
|
||||||
|
dictionary[f"{name}_ping_time"] = "Not found"
|
||||||
|
|
||||||
|
dictionary[f"{name}_ping_stats"] = result.stdout
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
dictionary[f"{name}_ping error"] = f"{e}"
|
||||||
|
|
||||||
|
return dictionary
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_ping(
|
||||||
|
dictionary: dict, base_address: str, relay_address: str, name: str
|
||||||
|
) -> dict:
|
||||||
|
try:
|
||||||
|
base_ping = float(dictionary[f"{base_address}_ping_time"])
|
||||||
|
relay_ping = float(dictionary[f"{relay_address}_ping_time"])
|
||||||
|
calculated_ping = base_ping - relay_ping
|
||||||
|
dictionary[f"{name}_c_ping_time"] = calculated_ping
|
||||||
|
except Exception as e:
|
||||||
|
dictionary[f"{name}_c_ping error"] = f"{e}"
|
||||||
|
|
||||||
|
return dictionary
|
||||||
|
|
||||||
|
|
||||||
|
def relay_iperf(
|
||||||
|
filename: str, base_address: str, relay_address: str, duration: str
|
||||||
|
) -> None:
|
||||||
|
collect_iperf(
|
||||||
|
filename=filename, server_ip=base_address, duration=duration, stations="eg"
|
||||||
|
)
|
||||||
|
collect_iperf(
|
||||||
|
filename=filename, server_ip=relay_address, duration=duration, stations="er"
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
collect_iperf_remote(filename=filename)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error collecting relay -> ground iperf: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
# Collect and send data continuously
|
||||||
|
def collect_data(
|
||||||
|
filename: str, base_address: str, relay_address: str, interval: int
|
||||||
|
) -> None:
|
||||||
|
global running
|
||||||
|
|
||||||
|
while running:
|
||||||
|
data = {}
|
||||||
|
data = get_current_location(dictionary=data)
|
||||||
|
data = get_modem_cops(dictionary=data)
|
||||||
|
data = get_modem_creg(dictionary=data)
|
||||||
|
data = get_modem_csq(dictionary=data)
|
||||||
|
data = get_modem_rsrp(dictionary=data)
|
||||||
|
data = get_modem_rsrq(dictionary=data)
|
||||||
|
data = get_modem_sinr(dictionary=data)
|
||||||
|
data = get_modem_cpol(dictionary=data)
|
||||||
|
data = get_modem_qnwcfg(dictionary=data)
|
||||||
|
data = get_modem_qnwinfo(dictionary=data)
|
||||||
|
data = get_modem_qspn(dictionary=data)
|
||||||
|
data = ping_basestation(
|
||||||
|
dictionary=data, name="eg", address=base_address
|
||||||
|
) # edge to ground
|
||||||
|
data = ping_basestation(
|
||||||
|
dictionary=data, name="er", address=relay_address
|
||||||
|
) # edge to relay
|
||||||
|
data = calculate_ping(
|
||||||
|
dictionary=data,
|
||||||
|
base_address=base_address,
|
||||||
|
relay_address=relay_address,
|
||||||
|
name="rg",
|
||||||
|
) # relay to ground
|
||||||
|
data["timestamp"] = time.time()
|
||||||
|
|
||||||
|
# Send to server
|
||||||
|
print(f"\nPing Time: {data.get('ping_time')}")
|
||||||
|
print(
|
||||||
|
f"RSRP: {data.get('RSRP PRX')} {data.get('RSRP DRX')} {data.get('RSRP RX2')} {data.get('RSRP RX3')}"
|
||||||
|
)
|
||||||
|
print(f"Service: {data.get('network information')}")
|
||||||
|
|
||||||
|
save_data_to_json(data=data, filename=filename)
|
||||||
|
|
||||||
|
time.sleep(interval)
|
||||||
|
|
||||||
|
|
||||||
|
def set_parameters():
|
||||||
|
set_modem = (
|
||||||
|
input(
|
||||||
|
"Do you want limit the modem to NR5G without roaming? (Not recommended if PLMN is not 001) (y/n )"
|
||||||
|
)
|
||||||
|
.strip()
|
||||||
|
.lower()
|
||||||
|
)
|
||||||
|
while set_modem not in ("y", "yes", "n", "no"):
|
||||||
|
set_modem = input("Your response must be y or n ").strip().lower()
|
||||||
|
if set_modem in ("y", "yes"):
|
||||||
|
print("Setting configs...")
|
||||||
|
set_configs()
|
||||||
|
|
||||||
|
base_address = (
|
||||||
|
input("Enter the base station (ground) ip address (Default is 10.46.0.1): ")
|
||||||
|
.strip()
|
||||||
|
.lower()
|
||||||
|
or "10.46.0.1"
|
||||||
|
)
|
||||||
|
relay_address = (
|
||||||
|
input("Enter the relay station ip address (Default is 10.45.0.1): ")
|
||||||
|
.strip()
|
||||||
|
.lower()
|
||||||
|
or "10.45.0.1"
|
||||||
|
)
|
||||||
|
folder_name = (
|
||||||
|
input("Enter the log folder name (Default is boat_relay_sept): ")
|
||||||
|
.strip()
|
||||||
|
.lower()
|
||||||
|
or "boat_relay_sept"
|
||||||
|
)
|
||||||
|
interval = int(
|
||||||
|
input(
|
||||||
|
"Enter the time interval (s) in between pings/modem data collection (Default is 5): "
|
||||||
|
)
|
||||||
|
.strip()
|
||||||
|
.lower()
|
||||||
|
or 5
|
||||||
|
)
|
||||||
|
iperf_duration = int(
|
||||||
|
input("Enter the iperf test duration (s) (Default is 5): ").strip().lower() or 5
|
||||||
|
)
|
||||||
|
|
||||||
|
return base_address, relay_address, folder_name, interval, iperf_duration
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
base_address, relay_address, folder_name, interval, iperf_duration = (
|
||||||
|
set_parameters()
|
||||||
|
)
|
||||||
|
|
||||||
|
foldername = f"data/{folder_name}"
|
||||||
|
filename = foldername + "/test_" + str(int(time.time())) + ".json"
|
||||||
|
os.makedirs(foldername, exist_ok=True)
|
||||||
|
|
||||||
|
print(
|
||||||
|
"Type 'l' to set basestation location, 'b' to begin, "
|
||||||
|
"'s' to stop, 'i' to run an iperf test, or 'x' to exit:"
|
||||||
|
)
|
||||||
|
while True:
|
||||||
|
command = input("> ").strip().lower()
|
||||||
|
if command == "b" and not running:
|
||||||
|
print("Starting data collection...")
|
||||||
|
running = True
|
||||||
|
threading.Thread(
|
||||||
|
target=collect_data,
|
||||||
|
args=(filename, base_address, relay_address, interval),
|
||||||
|
).start()
|
||||||
|
elif command == "l":
|
||||||
|
base_location_data = set_base_location()
|
||||||
|
save_data_to_json(data=base_location_data, filename=filename)
|
||||||
|
elif command == "i":
|
||||||
|
threading.Thread(
|
||||||
|
target=relay_iperf,
|
||||||
|
args=(filename, base_address, relay_address, iperf_duration),
|
||||||
|
).start()
|
||||||
|
elif command == "s" and running:
|
||||||
|
print("Stopping data collection...")
|
||||||
|
running = False
|
||||||
|
elif command == "x":
|
||||||
|
running = False
|
||||||
|
break
|
||||||
|
elif command not in ["l", "b", "s", "i", "x"]:
|
||||||
|
print("Invalid command. Type 'l', 'b', 's', 'i', or 'x'.")
|
55
relay_to_ground_iperf.py
Normal file
55
relay_to_ground_iperf.py
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import socket
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
|
||||||
|
GROUND_IP = "10.46.0.1" # gNodeB IP of ground station
|
||||||
|
PORT = 5005 # port to listen on for commands
|
||||||
|
BUFFER_SIZE = 4096
|
||||||
|
|
||||||
|
|
||||||
|
def run_iperf(normal=True):
|
||||||
|
"""Run iperf3 to ground. normal=True -> normal test, False -> reverse test."""
|
||||||
|
cmd = ["iperf3", "-c", GROUND_IP, "-t", "5"]
|
||||||
|
if not normal:
|
||||||
|
cmd.append("-R") # reverse mode
|
||||||
|
try:
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||||||
|
return result.stdout + result.stderr
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
return "[Relay] iperf test timed out\n"
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
sock.bind(("0.0.0.0", PORT))
|
||||||
|
print(f"[Relay] Listening for commands on port {PORT}")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
data, addr = sock.recvfrom(BUFFER_SIZE)
|
||||||
|
command = data.decode().strip()
|
||||||
|
print(f"[Relay] Received command '{command}' from {addr}")
|
||||||
|
|
||||||
|
if command.lower() == "start":
|
||||||
|
# Run normal test
|
||||||
|
output_normal = run_iperf(normal=True)
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
# Run reverse test
|
||||||
|
output_reverse = run_iperf(normal=False)
|
||||||
|
|
||||||
|
# Combine results
|
||||||
|
combined = (
|
||||||
|
"\n=== Normal Test (Relay → Ground) ===\n"
|
||||||
|
+ output_normal
|
||||||
|
+ "\n=== Reverse Test (Ground → Relay) ===\n"
|
||||||
|
+ output_reverse
|
||||||
|
)
|
||||||
|
|
||||||
|
# Send results back in chunks
|
||||||
|
for i in range(0, len(combined), BUFFER_SIZE):
|
||||||
|
sock.sendto(combined[i : i + BUFFER_SIZE].encode(), addr)
|
||||||
|
print(f"[Relay] Sent results back to {addr}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user