Skip to content

Commit aebbbb6

Browse files
BradG13531patrickelectric
authored andcommitted
Changed logging feature on omniscan450.py to log .svlog files
1 parent 3dfcd10 commit aebbbb6

File tree

2 files changed

+137
-48
lines changed

2 files changed

+137
-48
lines changed

examples/omniscan450Example.py

Lines changed: 89 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import signal
1313
import sys
1414
import os
15+
from pathlib import Path
1516
from datetime import datetime
1617

1718
##Parse Command line options
@@ -23,7 +24,7 @@
2324
parser.add_argument('--udp', action="store", required=False, type=str, help="Omniscan IP:Port. E.g: 192.168.2.92:51200")
2425
parser.add_argument('--tcp', action="store", required=False, type=str, help="Omniscan IP:Port. E.g: 192.168.2.92:51200")
2526
parser.add_argument('--range', action="store", required=False, type=str, help="Set range. E.g: 5000 or 0:5000")
26-
parser.add_argument('--log', action="store", nargs='?', const=True, type=str, help="Log filename. Will log if it doesn't exist, or replay if it does. Blank creates new log.")
27+
parser.add_argument('--log', action="store", nargs='?', const=True, type=str, help="Log filename and/or directory path. Will create new log if blank or directory is specified. Will replay if file is specified and exists.")
2728
args = parser.parse_args()
2829
if args.device is None and args.udp is None and args.tcp is None and args.log is None:
2930
parser.print_help()
@@ -42,37 +43,52 @@ def signal_handler(sig, frame):
4243

4344
signal.signal(signal.SIGINT, signal_handler)
4445

45-
# Make a new Omniscan450
46-
myOmniscan450 = Omniscan450()
46+
# Check for log argument and make new Omniscan450
47+
# If no .svlog is specified, create one using default directory
48+
# If directory specified, .svlog be created in specified directory
49+
# If a .svlog is specified, existing log will be opened
50+
new_log = False
51+
log_path = ""
52+
replay_path = None
53+
if args.log is not None:
54+
if args.log is True:
55+
# Logging to default directory
56+
myOmniscan450 = Omniscan450(logging=True)
57+
print(f"Logging to new file: {myOmniscan450.current_log}")
58+
new_log = True
59+
elif isinstance(args.log, str):
60+
log_path = Path(args.log).expanduser().resolve()
61+
62+
if log_path.suffix == ".svlog":
63+
if log_path.exists() and log_path.is_file():
64+
# File exists, replaying
65+
new_log = False
66+
myOmniscan450 = Omniscan450(logging=False)
67+
replay_path = log_path
68+
print(f"Replaying from: {replay_path}")
69+
# TODO add default path logic
70+
else:
71+
raise FileNotFoundError(f"Log file not found: {log_path}")
72+
73+
elif log_path.is_dir() or log_path.suffix == "":
74+
# Path is directory, logging to that directory
75+
myOmniscan450 = Omniscan450(logging=True, log_directory=log_path)
76+
print(f"Logging to new file: {myOmniscan450.current_log}")
77+
new_log = True
78+
79+
else:
80+
raise ValueError(f"Invalid log argument: {args.log}")
81+
else:
82+
log_filename = None
83+
4784
if args.device is not None:
4885
myOmniscan450.connect_serial(args.device, args.baudrate)
4986
elif args.udp is not None:
5087
(host, port) = args.udp.split(':')
5188
myOmniscan450.connect_udp(host, int(port))
5289
elif args.tcp is not None:
5390
(host, port) = args.tcp.split(':')
54-
myOmniscan450.connect_tcp(host, int(port))
55-
56-
# Check for log argument
57-
# If no log is specified, create one using date and time
58-
# If a log is specified, existing log will be opened
59-
new_log = False
60-
if args.log is not None:
61-
if args.log is True:
62-
log_filename = datetime.now().strftime("omniscan-%Y-%m-%d_%H-%M-%S.txt")
63-
elif isinstance(args.log, str):
64-
log_filename = args.log
65-
else:
66-
log_filename = None
67-
68-
if log_filename:
69-
log_path = os.path.join("logs/omniscan", log_filename)
70-
if os.path.exists(log_path):
71-
print(f"Replaying from existing log file: {log_filename}")
72-
new_log = False
73-
else:
74-
print(f"Logging to new file: {log_filename}")
75-
new_log = True
91+
myOmniscan450.connect_tcp(host, int(port))
7692

7793
if args.log is None or new_log:
7894
if myOmniscan450.initialize() is False:
@@ -91,24 +107,46 @@ def signal_handler(sig, frame):
91107

92108
# Running Omniscan from existing log file
93109
if args.log is not None and not new_log:
94-
os.makedirs("logs/omniscan", exist_ok=True)
95-
log_path = os.path.join("logs/omniscan", log_filename)
96110
with open(log_path, 'rb') as f:
111+
while True:
112+
start_bytes = f.read(2)
113+
if len(start_bytes) < 2:
114+
break # EOF
115+
116+
if start_bytes != b'BR':
117+
print("Invalid start bytes. Skipping...")
118+
continue
119+
120+
header = f.read(6)
121+
if len(header) < 6:
122+
print("Incomplete header. Ending replay.")
123+
break
124+
125+
payload_length = int.from_bytes(header[0:2], 'little')
126+
total_len = 2 + 2 + 2 + 2 + payload_length + 2 # BR + num payload bytes + packet id + reserved + payload + checksum
127+
128+
remaining = payload_length + 2
129+
rest = f.read(remaining)
130+
131+
if len(rest) < remaining:
132+
print("Incomplete payload or checksum. Ending replay.")
133+
134+
msg_bytes = start_bytes + header + rest
135+
data = PingMessage(msg_data=msg_bytes)
136+
137+
# print(data)
138+
139+
# Printing the same results as if directly connected to the Omniscan
140+
scaled_result = Omniscan450.scale_power(data)
141+
# for i in range(len(scaled_result)):
142+
# print(f"{i+1}: Raw: {data.pwr_results[i]}\tScaled: {scaled_result[i]}dB")
143+
print(f"Min power: {data.min_pwr_db} dB")
144+
print(f"Max power: {data.max_pwr_db} dB")
145+
print(f"Average power: {sum(scaled_result) / len(scaled_result)}")
146+
97147
raw_bytes = f.read()
98148
data = PingMessage(msg_data=raw_bytes)
99149

100-
if data:
101-
print(data)
102-
103-
# Printing the same results as if directly connected to the Omniscan
104-
scaled_result = Omniscan450.scale_power(data)
105-
for i in range(len(scaled_result)):
106-
print(f"{i+1}: Raw: {data.pwr_results[i]}\tScaled: {scaled_result[i]}dB")
107-
print(f"Min power: {data.min_pwr_db} dB")
108-
print(f"Max power: {data.max_pwr_db} dB")
109-
else:
110-
print("Failed to get report")
111-
112150
# Connected to physical omniscan
113151
else:
114152
if args.range is not None:
@@ -148,15 +186,18 @@ def signal_handler(sig, frame):
148186
# )
149187

150188
# View power results
151-
data = myOmniscan450.wait_message([definitions.OMNISCAN450_OS_MONO_PROFILE])
152-
if data:
153-
scaled_result = Omniscan450.scale_power(data)
154-
for i in range(len(scaled_result)):
155-
print(f"{i+1}: Raw: {data.pwr_results[i]}\tScaled: {scaled_result[i]}dB")
156-
print(f"Min power: {data.min_pwr_db} dB")
157-
print(f"Max power: {data.max_pwr_db} dB")
158-
else:
159-
print("Failed to get report")
189+
while True:
190+
data = myOmniscan450.wait_message([definitions.OMNISCAN450_OS_MONO_PROFILE])
191+
if data:
192+
print("Message Recieved")
193+
# scaled_result = Omniscan450.scale_power(data)
194+
# for i in range(len(scaled_result)):
195+
# print(f"{i+1}: Raw: {data.pwr_results[i]}\tScaled: {scaled_result[i]}dB")
196+
# print(f"Min power: {data.min_pwr_db} dB")
197+
# print(f"Max power: {data.max_pwr_db} dB")
198+
199+
else:
200+
print("Failed to get report")
160201

161202
# Disable pinging and close socket
162203
myOmniscan450.control_os_ping_params(enable=0)

generate/templates/omniscan450.py.in

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,21 @@ import time
1515
import math
1616
import struct
1717
import socket
18+
from datetime import datetime
19+
from pathlib import Path
20+
21+
MAX_LOG_SIZE_MB = 500
1822

1923
class Omniscan450(PingDevice):
24+
def __init__(self, logging = False, log_directory = None):
25+
super().__init__()
26+
self.logging = logging
27+
self.log_directory = log_directory
28+
self.bytes_written = None
29+
self.current_log = None
30+
if logging:
31+
self.new_log(log_directory)
32+
2033
def initialize(self):
2134
if (self.readDeviceInformation() is None):
2235
return False
@@ -114,6 +127,39 @@ class Omniscan450(PingDevice):
114127
final_power_results = tuple(scaled_power_results)
115128
return final_power_results
116129

130+
# Creates a new log file
131+
def new_log(self, log_directory=None):
132+
dt = datetime.now()
133+
save_name = dt.strftime("%Y-%m-%d-%H-%M")
134+
135+
if log_directory is None:
136+
project_root = Path.cwd().parent
137+
log_directory = project_root / "logs/omniscan"
138+
else:
139+
log_directory = Path(log_directory)
140+
141+
log_directory.mkdir(parents=True, exist_ok=True)
142+
143+
log_path = log_directory / f"{save_name}.svlog"
144+
145+
if log_path.exists():
146+
raise FileExistsError(f"Log file already exists: {log_path}")
147+
148+
self.current_log = log_path
149+
self.bytes_written = 0
150+
151+
# Write data to .svlog file
152+
def write_data(self, msg):
153+
if not self.logging:
154+
return
155+
156+
if self.bytes_written > MAX_LOG_SIZE_MB * 1000000:
157+
self.new_log(log_directory=self.log_directory)
158+
159+
with open(self.current_log, 'ab') as f:
160+
f.write(msg.msg_data)
161+
self.bytes_written += len(msg.msg_data)
162+
117163
# Override wait_message to format power results before returning
118164
def wait_message(self, message_ids, timeout=0.5):
119165
tstart = time.time()
@@ -126,6 +172,8 @@ class Omniscan450(PingDevice):
126172
msg.pwr_results = power_results
127173

128174
if msg.message_id in message_ids:
175+
if self.logging:
176+
self.write_data(msg)
129177
return msg
130178
time.sleep(0.005)
131179
return None

0 commit comments

Comments
 (0)