Files
dtsstreaming/chapter10_packet.py

104 lines
3.9 KiB
Python
Raw Normal View History

2025-07-24 10:50:29 -04:00
#!/usr/bin/env python3
"""
Chapter 10 Packet class for IRIG106 Chapter 10 frame parsing
"""
import struct
from typing import Dict, Optional
try:
from scapy.layers.inet import IP, UDP
except ImportError:
print("Error: scapy library not found. Install with: pip install scapy")
exit(1)
class Chapter10Packet:
"""Represents an IRIG106 Chapter 10 packet"""
def __init__(self, packet, original_frame_num: Optional[int] = None):
"""
Initialize Chapter 10 packet from raw scapy packet
Args:
packet: Raw scapy packet
original_frame_num: Original frame number in PCAP file
"""
self.raw_packet = packet
self.original_frame_num: Optional[int] = original_frame_num
# Extract basic packet info
self.timestamp = float(packet.time)
self.packet_size = len(packet)
# Extract IP/UDP info if available
if packet.haslayer(IP) and packet.haslayer(UDP):
ip_layer = packet[IP]
udp_layer = packet[UDP]
self.src_ip = ip_layer.src
self.dst_ip = ip_layer.dst
self.src_port = udp_layer.sport
self.dst_port = udp_layer.dport
self.payload = bytes(udp_layer.payload)
else:
self.src_ip = ""
self.dst_ip = ""
self.src_port = 0
self.dst_port = 0
self.payload = bytes()
# Parse Chapter 10 header
self.ch10_header = self._parse_ch10_header()
def _parse_ch10_header(self) -> Optional[Dict]:
"""Parse Chapter 10 header from payload"""
if len(self.payload) < 28: # Minimum payload size (4-byte prefix + 24-byte Ch10 header)
return None
try:
# Look for Ch10 sync pattern in first several bytes
ch10_offset = None
for offset in range(min(8, len(self.payload) - 24)):
sync_pattern = struct.unpack('<H', self.payload[offset:offset+2])[0]
if sync_pattern == 0xEB25: # Ch10 sync pattern
ch10_offset = offset
break
if ch10_offset is None:
return None
# Parse Chapter 10 header starting at found offset
base = ch10_offset
sync_pattern = struct.unpack('<H', self.payload[base:base+2])[0]
channel_id = struct.unpack('<H', self.payload[base+2:base+4])[0]
packet_length = struct.unpack('<I', self.payload[base+4:base+8])[0]
data_length = struct.unpack('<I', self.payload[base+8:base+12])[0]
header_version = self.payload[base+12]
sequence_number = self.payload[base+13]
packet_flags = self.payload[base+14]
data_type = self.payload[base+15]
rtc_low = struct.unpack('<I', self.payload[base+16:base+20])[0]
rtc_high = struct.unpack('<H', self.payload[base+20:base+22])[0]
checksum = struct.unpack('<H', self.payload[base+22:base+24])[0]
# Store the offset for reference
self.ch10_offset = ch10_offset
return {
'sync_pattern': f'0x{sync_pattern:04X}',
'channel_id': channel_id,
'packet_length': packet_length,
'data_length': data_length,
'header_version': header_version,
'sequence_number': sequence_number,
'packet_flags': f'0x{packet_flags:02X}',
'data_type': f'0x{data_type:02X}',
'rtc_low': rtc_low,
'rtc_high': rtc_high,
'checksum': f'0x{checksum:04X}',
'rtc_timestamp': (rtc_high << 32) | rtc_low,
'ch10_offset': ch10_offset
}
except (struct.error, IndexError):
return None