Organizes 11 projects for Cerbo GX/Venus OS into a single repository: - axiom-nmea: Raymarine LightHouse protocol decoder - dbus-generator-ramp: Generator current ramp controller - dbus-lightning: Blitzortung lightning monitor - dbus-meteoblue-forecast: Meteoblue weather forecast - dbus-no-foreign-land: noforeignland.com tracking - dbus-tides: Tide prediction from depth + harmonics - dbus-vrm-history: VRM cloud history proxy - dbus-windy-station: Windy.com weather upload - mfd-custom-app: MFD app deployment package - venus-html5-app: Custom Victron HTML5 app fork - watermaker: Watermaker PLC control UI Adds root README, .gitignore, project template, and per-project .gitignore files. Sensitive config files excluded via .gitignore with .example templates provided. Made-with: Cursor
79 lines
2.6 KiB
Python
79 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Debug wind extraction by examining actual packet bytes."""
|
|
|
|
import struct
|
|
|
|
PCAP_MAGIC = 0xa1b2c3d4
|
|
|
|
def decode_float(data, offset):
|
|
if offset + 4 > len(data):
|
|
return None
|
|
try:
|
|
return struct.unpack('<f', data[offset:offset+4])[0]
|
|
except:
|
|
return None
|
|
|
|
def read_pcap(filename):
|
|
packets = []
|
|
with open(filename, 'rb') as f:
|
|
header = f.read(24)
|
|
magic = struct.unpack('<I', header[0:4])[0]
|
|
swapped = magic == 0xd4c3b2a1
|
|
endian = '>' if swapped else '<'
|
|
|
|
while True:
|
|
pkt_header = f.read(16)
|
|
if len(pkt_header) < 16:
|
|
break
|
|
ts_sec, ts_usec, incl_len, orig_len = struct.unpack(f'{endian}IIII', pkt_header)
|
|
pkt_data = f.read(incl_len)
|
|
if len(pkt_data) < incl_len:
|
|
break
|
|
|
|
if len(pkt_data) > 42 and pkt_data[12:14] == b'\x08\x00':
|
|
ip_header_len = (pkt_data[14] & 0x0F) * 4
|
|
payload_start = 14 + ip_header_len + 8
|
|
if payload_start < len(pkt_data):
|
|
packets.append(pkt_data[payload_start:])
|
|
return packets
|
|
|
|
packets = read_pcap("raymarine_sample.pcap")
|
|
|
|
# Find packets of different sizes
|
|
sizes_seen = {}
|
|
for pkt in packets:
|
|
plen = len(pkt)
|
|
if plen not in sizes_seen:
|
|
sizes_seen[plen] = pkt
|
|
|
|
print("Examining wind data at known offsets:\n")
|
|
|
|
for target_size in [344, 446, 788, 888, 1472]:
|
|
# Find a packet close to this size
|
|
for plen, pkt in sizes_seen.items():
|
|
if abs(plen - target_size) <= 10:
|
|
print(f"=== Packet size {plen} ===")
|
|
|
|
# Show bytes around expected wind offsets
|
|
if 340 <= plen <= 350:
|
|
offsets = [0x00a0, 0x00a5, 0x00c3, 0x00c8]
|
|
elif 440 <= plen <= 500:
|
|
offsets = [0x00a7, 0x00ac, 0x00ca, 0x00b1]
|
|
elif 780 <= plen <= 900:
|
|
offsets = [0x0090, 0x00c5, 0x00ca, 0x00cf]
|
|
elif 1400 <= plen <= 1500:
|
|
offsets = [0x00fc, 0x0101, 0x0106]
|
|
else:
|
|
offsets = []
|
|
|
|
for off in offsets:
|
|
if off + 8 <= plen:
|
|
hex_bytes = ' '.join(f'{b:02x}' for b in pkt[off:off+8])
|
|
float_val = decode_float(pkt, off)
|
|
# Also try treating as m/s and rad
|
|
speed_kts = float_val * 1.94384 if float_val else 0
|
|
dir_deg = float_val * 57.2958 if float_val else 0
|
|
print(f" 0x{off:04x}: {hex_bytes} -> float={float_val:.4f} ({speed_kts:.1f} kts or {dir_deg:.1f}°)")
|
|
print()
|
|
break
|