Skip to content

Commit 215e65e

Browse files
BradG13531patrickelectric
authored andcommitted
Added svlog support to omniscan450
1 parent aebbbb6 commit 215e65e

File tree

2 files changed

+176
-72
lines changed

2 files changed

+176
-72
lines changed

examples/omniscan450Example.py

Lines changed: 41 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
# Signal handler to stop pinging on the Omniscan450
3434
def signal_handler(sig, frame):
35-
print("Stopping pinging on Omniscan450...")
35+
print("\nStopping pinging on Omniscan450...")
3636
myOmniscan450.control_os_ping_params(enable=0)
3737
if myOmniscan450.iodev:
3838
try:
@@ -50,14 +50,21 @@ def signal_handler(sig, frame):
5050
new_log = False
5151
log_path = ""
5252
replay_path = None
53+
default_dir = Path("logs/omniscan").resolve()
5354
if args.log is not None:
5455
if args.log is True:
5556
# Logging to default directory
56-
myOmniscan450 = Omniscan450(logging=True)
57-
print(f"Logging to new file: {myOmniscan450.current_log}")
57+
default_dir.mkdir(parents=True, exist_ok=True)
58+
myOmniscan450 = Omniscan450(logging=True, log_directory=default_dir)
59+
print(f"Logging to new file in: {default_dir}")
5860
new_log = True
5961
elif isinstance(args.log, str):
60-
log_path = Path(args.log).expanduser().resolve()
62+
log_path = Path(args.log).expanduser()
63+
64+
if log_path.suffix == ".svlog" and log_path.parent == Path("."):
65+
log_path = default_dir / log_path.name
66+
67+
log_path = log_path.resolve()
6168

6269
if log_path.suffix == ".svlog":
6370
if log_path.exists() and log_path.is_file():
@@ -66,7 +73,6 @@ def signal_handler(sig, frame):
6673
myOmniscan450 = Omniscan450(logging=False)
6774
replay_path = log_path
6875
print(f"Replaying from: {replay_path}")
69-
# TODO add default path logic
7076
else:
7177
raise FileNotFoundError(f"Log file not found: {log_path}")
7278

@@ -78,8 +84,6 @@ def signal_handler(sig, frame):
7884

7985
else:
8086
raise ValueError(f"Invalid log argument: {args.log}")
81-
else:
82-
log_filename = None
8387

8488
if args.device is not None:
8589
myOmniscan450.connect_serial(args.device, args.baudrate)
@@ -95,8 +99,8 @@ def signal_handler(sig, frame):
9599
print("Failed to initialize Omniscan450!")
96100
exit(1)
97101

98-
data1 = myOmniscan450.get_device_information()
99-
print("Device type: %s" % data1["device_type"])
102+
data1 = myOmniscan450.readDeviceInformation()
103+
print("Device type: %s" % data1.device_type)
100104

101105
print("------------------------------------")
102106
print("Starting Omniscan450..")
@@ -109,43 +113,21 @@ def signal_handler(sig, frame):
109113
if args.log is not None and not new_log:
110114
with open(log_path, 'rb') as f:
111115
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)
116+
data = Omniscan450.read_packet(f)
130117

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)
118+
if data == None:
119+
break # EOF or bad packet
136120

137-
# print(data)
121+
if data.message_id == definitions.OMNISCAN450_OS_MONO_PROFILE:
122+
# print(data)
138123

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-
147-
raw_bytes = f.read()
148-
data = PingMessage(msg_data=raw_bytes)
124+
# Printing the same results as if directly connected to the Omniscan
125+
scaled_result = Omniscan450.scale_power(data)
126+
# for i in range(len(scaled_result)):
127+
# print(f"{i+1}: Raw: {data.pwr_results[i]}\tScaled: {scaled_result[i]}dB")
128+
# print(f"Min power: {data.min_pwr_db} dB")
129+
# print(f"Max power: {data.max_pwr_db} dB")
130+
print(f"Average power: {sum(scaled_result) / len(scaled_result)}")
149131

150132
# Connected to physical omniscan
151133
else:
@@ -186,18 +168,22 @@ def signal_handler(sig, frame):
186168
# )
187169

188170
# View power results
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")
171+
if new_log:
172+
print("Logging...\nCTRL+C to stop logging")
173+
try:
174+
while True:
175+
data = myOmniscan450.wait_message([definitions.OMNISCAN450_OS_MONO_PROFILE])
176+
if data and not new_log:
177+
pass
178+
scaled_result = Omniscan450.scale_power(data)
179+
for i in range(len(scaled_result)):
180+
print(f"{i+1}: Raw: {data.pwr_results[i]}\tScaled: {scaled_result[i]}dB")
181+
print(f"Min power: {data.min_pwr_db} dB")
182+
print(f"Max power: {data.max_pwr_db} dB")
183+
elif not data:
184+
print("Failed to get report")
185+
except KeyboardInterrupt:
186+
print("Stopping logging...")
201187

202188
# Disable pinging and close socket
203189
myOmniscan450.control_os_ping_params(enable=0)
@@ -206,9 +192,3 @@ def signal_handler(sig, frame):
206192
myOmniscan450.iodev.close()
207193
except Exception as e:
208194
print(f"Failed to close socket: {e}")
209-
210-
if new_log:
211-
os.makedirs("logs/omniscan", exist_ok=True)
212-
log_path = os.path.join("logs/omniscan", log_filename)
213-
with open(log_path, 'ab') as f:
214-
f.write(data.msg_data)

generate/templates/omniscan450.py.in

Lines changed: 135 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ import socket
1818
from datetime import datetime
1919
from pathlib import Path
2020

21+
# Imports for svlog header
22+
import json
23+
import os
24+
import sys
25+
import platform
26+
2127
MAX_LOG_SIZE_MB = 500
2228

2329
class Omniscan450(PingDevice):
@@ -27,12 +33,14 @@ class Omniscan450(PingDevice):
2733
self.log_directory = log_directory
2834
self.bytes_written = None
2935
self.current_log = None
30-
if logging:
31-
self.new_log(log_directory)
36+
{# if logging:
37+
self.new_log(log_directory) #}
3238

3339
def initialize(self):
3440
if (self.readDeviceInformation() is None):
3541
return False
42+
if self.logging:
43+
self.new_log(self.log_directory)
3644
return True
3745

3846
{% for msg in messages["get"]|sort %}
@@ -127,38 +135,154 @@ class Omniscan450(PingDevice):
127135
final_power_results = tuple(scaled_power_results)
128136
return final_power_results
129137

138+
# Reads a single packet from a file
139+
@staticmethod
140+
def read_packet(file):
141+
sync = file.read(2)
142+
if sync != b'BR':
143+
return None
144+
145+
payload_len_bytes = file.read(2)
146+
if len(payload_len_bytes) < 2:
147+
return None
148+
payload_len = int.from_bytes(payload_len_bytes, 'little')
149+
150+
msg_id = file.read(2)
151+
if len(msg_id) < 2:
152+
return None
153+
154+
remaining = 2 + payload_len + 2
155+
rest = file.read(remaining)
156+
if len(rest) < remaining:
157+
return None
158+
159+
msg_bytes = sync + payload_len_bytes + msg_id + rest
160+
return pingmessage.PingMessage(msg_data=msg_bytes)
161+
162+
# Builds the packet containing metadata for the beginning of .svlog
163+
def build_metadata_packet(self):
164+
165+
protocol = "tcp" # default fallback
166+
if self.iodev:
167+
if self.iodev.type == socket.SOCK_STREAM:
168+
protocol = "tcp"
169+
elif self.iodev.type == socket.SOCK_DGRAM:
170+
protocol = "udp"
171+
172+
if self.server_address:
173+
url = f"{protocol}://{self.server_address[0]}:{self.server_address[1]}"
174+
else:
175+
url = f"{protocol}://unknown"
176+
177+
content = {
178+
"session_id": 1,
179+
"session_uptime": 0.0,
180+
"session_devices": [
181+
{
182+
"url": url,
183+
"product_id": "os450"
184+
}
185+
],
186+
"session_platform": None,
187+
"session_clients": [],
188+
"session_plan_name": None,
189+
190+
"sonarlink_version": "",
191+
"os_hostname": platform.node(),
192+
"os_uptime": None,
193+
"os_version": platform.version(),
194+
"os_platform": platform.system().lower(),
195+
"os_release": platform.release(),
196+
197+
"process_path": sys.executable,
198+
"process_version": f"v{platform.python_version()}",
199+
"process_uptime": time.process_time(),
200+
"process_arch": platform.machine(),
201+
202+
"timestamp": datetime.utcnow().isoformat() + "Z",
203+
"timestamp_timezone_offset": -time.timezone // 60
204+
}
205+
206+
json_bytes = json.dumps(content, indent=2).encode("utf-8")
207+
208+
m = pingmessage.PingMessage(definitions.OMNISCAN450_JSON_WRAPPER)
209+
m.payload = json_bytes
210+
m.payload_length = len(json_bytes)
211+
212+
msg_data = bytearray()
213+
msg_data += b"BR"
214+
msg_data += m.payload_length.to_bytes(2, "little")
215+
msg_data += m.message_id.to_bytes(2, "little")
216+
msg_data += m.dst_device_id.to_bytes(1, "little")
217+
msg_data += m.src_device_id.to_bytes(1, "little")
218+
msg_data += m.payload
219+
220+
checksum = sum(msg_data) & 0xFFFF
221+
msg_data += bytearray(struct.pack(pingmessage.PingMessage.endianess + pingmessage.PingMessage.checksum_format, checksum))
222+
223+
m.msg_data = msg_data
224+
m.checksum = checksum
225+
226+
return m
227+
228+
# Enable logging
229+
def start_logging(self, new_log = False, log_directory = None):
230+
if self.logging:
231+
return
232+
233+
self.logging = True
234+
235+
if self.current_log is None or new_log:
236+
self.new_log(log_directory)
237+
238+
# Disable logging
239+
def stop_logging(self):
240+
self.logging = False
241+
130242
# Creates a new log file
131243
def new_log(self, log_directory=None):
132244
dt = datetime.now()
133245
save_name = dt.strftime("%Y-%m-%d-%H-%M")
134246

135247
if log_directory is None:
136248
project_root = Path.cwd().parent
137-
log_directory = project_root / "logs/omniscan"
249+
self.log_directory = project_root / "logs/omniscan"
138250
else:
139-
log_directory = Path(log_directory)
251+
self.log_directory = Path(log_directory)
140252

141253
log_directory.mkdir(parents=True, exist_ok=True)
142254

143255
log_path = log_directory / f"{save_name}.svlog"
144256

145257
if log_path.exists():
146-
raise FileExistsError(f"Log file already exists: {log_path}")
258+
log_path.unlink() # delete existing file (program was restarted quickly)
259+
{# raise FileExistsError(f"Log file already exists: {log_path}") #}
147260

148261
self.current_log = log_path
149262
self.bytes_written = 0
150263

264+
self.write_data(self.build_metadata_packet())
265+
151266
# Write data to .svlog file
152267
def write_data(self, msg):
153-
if not self.logging:
268+
if not self.logging or not self.current_log:
154269
return
155270

156-
if self.bytes_written > MAX_LOG_SIZE_MB * 1000000:
157-
self.new_log(log_directory=self.log_directory)
271+
try:
272+
if self.bytes_written > MAX_LOG_SIZE_MB * 1000000:
273+
self.new_log(log_directory=self.log_directory)
158274

159-
with open(self.current_log, 'ab') as f:
160-
f.write(msg.msg_data)
161-
self.bytes_written += len(msg.msg_data)
275+
with open(self.current_log, 'ab') as f:
276+
f.write(msg.msg_data)
277+
self.bytes_written += len(msg.msg_data)
278+
279+
except (OSError, IOError) as e:
280+
print(f"[LOGGING ERROR] Failed to write to log file {self.current_log}: {e}")
281+
self.stop_logging()
282+
283+
except Exception as e:
284+
print(f"[LOGGING ERROR] Unexpected error: {e}")
285+
self.stop_logging()
162286

163287
# Override wait_message to format power results before returning
164288
def wait_message(self, message_ids, timeout=0.5):

0 commit comments

Comments
 (0)