import requests
|
import struct
|
|
url = "http://39.99.43.227:8866/api/file/download/21b09df9-9232-4e38-a5cc-19458d324019_data.bin"
|
|
print(f"Downloading from: {url}")
|
print("-" * 60)
|
|
try:
|
response = requests.get(url, timeout=10)
|
|
print(f"Status Code: {response.status_code}")
|
print(f"Content-Type: {response.headers.get('Content-Type', 'N/A')}")
|
print(f"Content-Length: {response.headers.get('Content-Length', 'N/A')}")
|
print(f"Content-Disposition: {response.headers.get('Content-Disposition', 'N/A')}")
|
print("-" * 60)
|
|
if response.status_code == 200:
|
data = response.content
|
print(f"Downloaded {len(data)} bytes")
|
print("-" * 60)
|
|
# 首先查看原始字节
|
print(f"First 40 bytes (hex): {data[0:40].hex()}")
|
print(f"First 4 bytes as bytes: {[hex(b) for b in data[0:4]]}")
|
print("-" * 60)
|
|
if len(data) >= 40:
|
# 解析头部 (MowerPathHeader_t) - 小端字节序
|
# Offset 0-11: 基础信息
|
sof = struct.unpack('>H', data[0:2])[0] # 大端读取SOF
|
file_type = data[2]
|
version = data[3]
|
path_id = struct.unpack('<I', data[4:8])[0]
|
timestamp = struct.unpack('<I', data[8:12])[0]
|
|
# Offset 12-35: 保留与高精度数据
|
reserved = struct.unpack('<I', data[12:16])[0]
|
origin_lon = struct.unpack('<d', data[16:24])[0]
|
origin_lat = struct.unpack('<d', data[24:32])[0]
|
origin_alt = struct.unpack('<f', data[32:36])[0]
|
|
# Offset 36-39: 数量信息
|
boundary_count = struct.unpack('<H', data[36:38])[0]
|
path_count = struct.unpack('<H', data[38:40])[0]
|
|
print("Header parsed:")
|
print(f" SOF: 0x{sof:04X} (expected 0x55AA)")
|
print(f" Type: 0x{file_type:02X} (expected 0x3C)")
|
print(f" Version: 0x{version:02X} (expected 0x10)")
|
print(f" Path ID: {path_id}")
|
print(f" Timestamp: {timestamp}")
|
print(f" Reserved: {reserved}")
|
print(f" Origin: Lat={origin_lat:.8f}, Lon={origin_lon:.8f}, Alt={origin_alt:.2f}")
|
print(f" Boundary points: {boundary_count}")
|
print(f" Path points: {path_count}")
|
print("-" * 60)
|
|
# 验证格式
|
if sof == 0x55AA and file_type == 0x3C and version == 0x10:
|
print("✓ Header format is VALID")
|
|
# 计算预期数据大小
|
expected_size = 40 + (boundary_count + path_count) * 8 + 4
|
print(f"Expected total size: {expected_size} bytes (header + points + CRC32)")
|
print(f"Actual size: {len(data)} bytes")
|
|
if len(data) == expected_size:
|
print("✓ File size matches expected")
|
else:
|
print(f"✗ Size mismatch: {len(data) - expected_size:+d} bytes")
|
|
print("-" * 60)
|
|
# CRC32验证(测试多种CRC配置)
|
import binascii
|
import zlib
|
|
# 数据部分(不包括最后4字节CRC)
|
data_only = data[:-4]
|
crc32_stored = struct.unpack('<I', data[-4:])[0]
|
|
print(f"CRC32 Verification:")
|
print(f" Stored in file (last 4 bytes): 0x{crc32_stored:08X}")
|
print(f" Data size for CRC: {len(data_only)} bytes")
|
print()
|
|
# 测试不同的CRC32算法
|
# 1. binascii.crc32 (初始值0, 输出直接使用)
|
crc1 = binascii.crc32(data_only, 0) & 0xFFFFFFFF
|
print(f" 1. binascii.crc32(init=0): 0x{crc1:08X} {'✓ MATCH!' if crc1 == crc32_stored else ''}")
|
|
# 2. zlib.crc32 (初始值0)
|
crc2 = zlib.crc32(data_only, 0) & 0xFFFFFFFF
|
print(f" 2. zlib.crc32(init=0): 0x{crc2:08X} {'✓ MATCH!' if crc2 == crc32_stored else ''}")
|
|
# 3. binascii.crc32 取反(模拟最终XOR)
|
crc3 = ~binascii.crc32(data_only, 0) & 0xFFFFFFFF
|
print(f" 3. ~binascii.crc32(init=0): 0x{crc3:08X} {'✓ MATCH!' if crc3 == crc32_stored else ''}")
|
|
# 4. STM32默认:初始值0xFFFFFFFF,无最终XOR
|
crc4 = binascii.crc32(data_only, 0xFFFFFFFF) & 0xFFFFFFFF
|
print(f" 4. binascii.crc32(init=0xFFFFFFFF): 0x{crc4:08X} {'✓ MATCH!' if crc4 == crc32_stored else ''}")
|
|
# 5. STM32默认+最终XOR
|
crc5 = ~binascii.crc32(data_only, 0xFFFFFFFF) & 0xFFFFFFFF
|
print(f" 5. ~binascii.crc32(init=0xFFFFFFFF): 0x{crc5:08X} {'✓ MATCH!' if crc5 == crc32_stored else ''}")
|
else:
|
print("✗ Header format is INVALID")
|
print(f"First 40 bytes (hex): {data[0:40].hex()}")
|
else:
|
print(f"✗ File too small (only {len(data)} bytes)")
|
print(f"Content (hex): {data.hex()}")
|
else:
|
print(f"✗ HTTP Error: {response.status_code}")
|
print(f"Response body: {response.text[:500]}")
|
|
except requests.exceptions.RequestException as e:
|
print(f"✗ Request failed: {e}")
|