Files
VDES_Backend/报文模拟解析/模拟发送.py
2026-07-13 15:37:05 +08:00

350 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import struct
import math
def create_tcp_packet(packet_type, content):
"""创建符合VDES TCP协议的报文"""
# 报文帧头 (4字节)
header = b'####'
# 报文类型 (4字节大端)
type_field = struct.pack('>I', packet_type)
# 报文长度 (4字节大端内容长度)
length = len(content)
length_field = struct.pack('>I', length)
# 构建完整报文
packet = header + type_field + length_field + content
return packet
def create_gps_packet():
"""创建GPS解析数据报文(类型7)的内容"""
# 模拟GPS数据 (表11定义)
utc_time = 1680000000 # UTC时间 (8字节)
longitude = 1205000000 # 经度 (4字节东经120.5度)
latitude = 305000000 # 纬度 (4字节北纬30.5度)
altitude = 50 # 海拔高度 (4字节50米)
used_sats = 10 # 定位使用的卫星数 (2字节)
gps_sats = 8 # GPS卫星数 (2字节)
beidou_sats = 7 # 北斗卫星数 (2字节)
gps_status = 1 # GPS状态 (1字节单点定位)
position_mode = 3 # 定位模式 (1字节3D定位)
hdop = 2550 # 水平精度因子 (4字节25.5米)
speed = 1024 # 运动速度 (4字节10.24节)
direction = 359 # 运动方向 (4字节359度)
# 打包为二进制 (大端字节序)
content = struct.pack(
'>QiiiHHHBBIII', # 格式: Q(8),i(4),i(4),i(4),H(2),H(2),H(2),B(1),B(1),I(4),I(4),I(4)
utc_time,
longitude,
latitude,
altitude,
used_sats,
gps_sats,
beidou_sats,
gps_status,
position_mode,
hdop,
speed,
direction
)
return content
def create_ais_info_packet(demod_content):
"""创建解调信息报文(类型12)的内容"""
# 模拟解调信息数据
message_type = 12 # 消息类型 (1字节)
satellite_id = 1 # 卫星ID (1字节)
demodulator_id = 0 # 解调器编号 (1字节)
demod_slot = 1234 # 解调时隙 (2字节)
receive_delay = 5678 # 接收延迟 (2字节单位us)
snr = 25.75 # 信噪比 (2字节dB)
# 处理信噪比 (高8位整数部分低8位小数部分)
snr_int = int(snr)
snr_frac = int((snr - snr_int) * 100) # 转换为0-99的小数部分
snr_packed = (snr_int & 0xFF) << 8 | (snr_frac & 0xFF)
# 打包为二进制 (大端字节序)
content = struct.pack(
'>BBBHHH', # 格式: B(1),B(1),B(1),H(2),H(2),h(2)
message_type,
satellite_id,
demodulator_id,
demod_slot,
receive_delay,
snr_packed
)
return content + demod_content
def encode_demod_fields():
"""编码解调信息字段并打印解码结果"""
# 初始化二进制位列表
bits = []
# 示例数据
message_id = 1 # 消息ID (6 bits)
repeat_indicator = 0 # 转发指示符 (2 bits)
user_id = 123456789 # 用户ID/MMSI (30 bits)
navigation_status = 8 # 导航状态 (4 bits) - 航行中
rot = -128 # 旋转速率 (8 bits) - 无信息
sog = 102 # 地面航速 (10 bits) - 10.2节
position_accuracy = 1 # 位置准确度 (1 bit) - 高
longitude = 120.5 # 经度 (28 bits) - 东经120.5°
latitude = 30.5 # 纬度 (27 bits) - 北纬30.5°
cog = 900 # 地面航线 (12 bits) - 90.0°
true_heading = 90 # 实际航向 (9 bits) - 90°
timestamp = 30 # 时戳 (6 bits) - UTC秒
special_maneuver = 0 # 特定操纵指示符 (2 bits)
spare = 0 # 备用 (3 bits)
raim_flag = 0 # RAIM标志 (1 bit)
comm_state = 0 # 通信状态 (19 bits)
# 添加各个字段(按照协议顺序)
bits.append(format(message_id, '06b')) # 消息ID
bits.append(format(repeat_indicator, '02b')) # 转发指示符
bits.append(format(user_id, '030b')) # 用户ID
bits.append(format(navigation_status, '04b')) # 导航状态
# 旋转速率 (8位有符号整数)
rot_bits = rot & 0xFF
bits.append(format(rot_bits, '08b'))
# 地面航速 (10位)
bits.append(format(min(sog, 1023), '010b'))
# 位置准确度 (1位)
bits.append(str(position_accuracy))
# 经度 (28位)
# 转换为1/10,000分钟单位
longitude_min = int(longitude * 60 * 10000)
bits.append(format(longitude_min & 0x0FFFFFFF, '028b'))
# 纬度 (27位)
latitude_min = int(latitude * 60 * 10000)
bits.append(format(latitude_min & 0x07FFFFFF, '027b'))
# 地面航线 (12位)
bits.append(format(min(cog, 3600), '012b'))
# 实际航向 (9位)
bits.append(format(min(true_heading, 511), '09b'))
# 时戳 (6位)
bits.append(format(min(timestamp, 63), '06b'))
# 特定操纵指示符 (2位)
bits.append(format(special_maneuver, '02b'))
# 备用 (3位)
bits.append(format(spare, '03b'))
# RAIM标志 (1位)
bits.append(str(raim_flag))
# 通信状态 (19位)
bits.append(format(comm_state, '019b'))
# 合并所有位
bit_string = ''.join(bits)
# 验证总位数
total_bits = len(bit_string)
if total_bits != 168:
print(f"警告: 总位数应为168实际为{total_bits}")
# 将位字符串转换为字节
binary_int = int(bit_string, 2) # 将二进制字符串转换为整数
byte_length = (len(bit_string) + 7) // 8 # 计算需要的字节数
binary_data = binary_int.to_bytes(byte_length, 'big') # 转换为字节
return binary_data
# 生成AIS报文
demod_content = encode_demod_fields()
ais_data = create_ais_info_packet(demod_content)
ais_packet = create_tcp_packet(12, ais_data)
# print("完整报文字节长度:", len(final_packet))
# print("二进制表示:")
# print(final_packet)
# print(' '.join(f'{b:02x}' for b in final_packet))
# print('----------------------------------/n')
# 生成GPS报文
gps_content = create_gps_packet()
gps_packet = create_tcp_packet(7, gps_content)
# 打印二进制报文
# print("完整报文字节长度:", len(gps_packet))
# print("二进制表示:")
# print(gps_packet)
# print(' '.join(f'{b:02x}' for b in gps_packet))
def get_tcp_data(packet_data):
#判断帧头是否符合卓研
if packet_data[:4].decode('ascii') == '####':
print("开始解析报文帧")
packet_type = struct.unpack('>I', packet_data[4:8])[0] #获取报文类型 7为gps 12为ais
packet_lenth = struct.unpack('>I', packet_data[8:12])[0]
packet_content = packet_data[12:]
if packet_type == 7:
print(f"GPS内容长度: {packet_lenth} 字节")
data = get_gps_data(packet_content)
print(data)
elif packet_type == 12:
print(f"AIS内容长度: {packet_lenth} 字节")
data = get_ais_data(packet_content)
print(data)
def get_gps_data(packet_content):
fields = struct.unpack('>QiiiHHHBBIII', packet_content)
res = {}
res['utc_time'] = fields[0] # UTC时间 (8字节)
res['longitude'] = fields[1]/10000000 # 经度 (4字节东经120.5度)
res['latitude'] = fields[2]/10000000 # 纬度 (4字节北纬30.5度)
res['altitude'] = fields[3] # 海拔高度 (4字节50米)
res['used_sats'] = fields[4] # 定位使用的卫星数 (2字节)
res['gps_sats'] = fields[5] # GPS卫星数 (2字节)
res['beidou_sats'] = fields[6] # 北斗卫星数 (2字节)
res['gps_status'] = fields[7] # GPS状态 (1字节单点定位)
res['position_mode'] = fields[8] # 定位模式 (1字节3D定位)
res['hdop'] = fields[9]/10 # 水平精度因子 (4字节25.5米)
res['speed'] = fields[10]/100 # 运动速度 (4字节10.24节)
res['direction'] = fields[11] # 运动方向 (4字节359度)
return res
def get_ais_data(packet_content):
res ={}
demod_packet = packet_content[:9]
demod_data = packet_content[9:]
fields = struct.unpack('>BBBHHH', demod_packet)
res['message_type'] = fields[0]
res['satellite_id'] = fields[1]
res['demodulator_id'] = fields[2]
res['demod_slot'] = fields[3]
res['receive_delay'] = fields[4]
snr_packed = fields[5]
# 解析SNR
snr_int = (snr_packed >> 8) & 0xFF
snr_frac = snr_packed & 0xFF
res['snr'] = snr_int + snr_frac / 100.0
print(demod_data)
res['demod_data'] = get_demod_data(demod_data)
return res
def get_demod_data(bit_string):
# 如果输入是字节类型,先转换为二进制字符串
if isinstance(bit_string, bytes):
bit_string = ''.join(format(byte, '08b') for byte in bit_string)
pos = 0
decoded = {}
decoded['message_id'] = int(bit_string[pos:pos+6], 2) # 消息ID (6 bits)
pos += 6
decoded['repeat_indicator'] = int(bit_string[pos:pos+2], 2) # 转发指示符 (2 bits)
pos += 2
decoded['user_id'] = int(bit_string[pos:pos+30], 2) # 用户ID/MMSI (30 bits)
pos += 30
decoded['navigation_status'] = int(bit_string[pos:pos+4], 2) # 导航状态 (4 bits)
pos += 4
# 旋转速率 (8位有符号整数)
rot_value = int(bit_string[pos:pos+8], 2)
if rot_value > 127:
rot_value -= 256
decoded['rot'] = rot_value
pos += 8
decoded['sog'] = int(bit_string[pos:pos+10], 2) # 地面航速 (10 bits)
pos += 10
decoded['position_accuracy'] = int(bit_string[pos], 2) # 位置准确度 (1 bit)
pos += 1
# 经度 (28位)
longitude_value = int(bit_string[pos:pos+28], 2)
decoded['longitude'] = longitude_value / (60 * 10000) # 转换为度
pos += 28
# 纬度 (27位)
latitude_value = int(bit_string[pos:pos+27], 2)
decoded['latitude'] = latitude_value / (60 * 10000) # 转换为度
pos += 27
decoded['cog'] = int(bit_string[pos:pos+12], 2) # 地面航线 (12 bits)
pos += 12
decoded['true_heading'] = int(bit_string[pos:pos+9], 2) # 实际航向 (9 bits)
pos += 9
decoded['timestamp'] = int(bit_string[pos:pos+6], 2) # 时戳 (6 bits)
pos += 6
decoded['special_maneuver'] = int(bit_string[pos:pos+2], 2) # 特定操纵指示符 (2 bits)
pos += 2
decoded['spare'] = int(bit_string[pos:pos+3], 2) # 备用 (3 bits)
pos += 3
decoded['raim_flag'] = int(bit_string[pos], 2) # RAIM标志 (1 bit)
pos += 1
decoded['comm_state'] = int(bit_string[pos:pos+19], 2) # 通信状态 (19 bits)
return decoded
get_tcp_data(ais_packet)
# def get_demod_data(bit_string):
# pos = 0
# message_id = int(bit_string[pos:pos+6], 2) # 消息ID (6 bits)
# pos += 6
# repeat_indicator = int(bit_string[pos:pos+2], 2) # 转发指示符 (2 bits)
# pos += 2
# user_id = int(bit_string[pos:pos+30], 2) # 用户ID/MMSI (30 bits)
# pos += 30
# navigation_status = int(bit_string[pos:pos+4], 2) # 导航状态 (4 bits) - 航行中
# pos += 4
# rot_value = int(bit_string[pos:pos+8], 2)
# # 转换为有符号整数
# if rot_value > 127:
# rot_value -= 256
# rot = rot_value # 旋转速率 (8 bits) - 无信息
# pos += 8
# sog = int(bit_string[pos:pos+10], 2) # 地面航速 (10 bits) - 10.2节
# pos += 10
# position_accuracy = int(bit_string[pos], 2) # 位置准确度 (1 bit) - 高
# pos += 1
# longitude_value = int(bit_string[pos:pos+28], 2)
# # 转换为度
# longitude_deg = longitude_value / (60 * 10000)
# longitude = longitude_deg # 经度 (28 bits) - 东经120.5°
# pos += 28
# latitude_value = int(bit_string[pos:pos+27], 2)
# # 转换为度
# latitude_deg = latitude_value / (60 * 10000)
# latitude = latitude_deg # 纬度 (27 bits) - 北纬30.5°
# pos += 27
# cog = int(bit_string[pos:pos+12], 2) # 地面航线 (12 bits) - 90.0°
# pos += 12
# true_heading = int(bit_string[pos:pos+9], 2) # 实际航向 (9 bits) - 90°
# pos += 9
# timestamp = int(bit_string[pos:pos+6], 2) # 时戳 (6 bits) - UTC秒
# pos += 6
# special_maneuver = int(bit_string[pos:pos+2], 2) # 特定操纵指示符 (2 bits)
# pos += 2
# spare = int(bit_string[pos:pos+3], 2) # 备用 (3 bits)
# pos += 3
# raim_flag = int(bit_string[pos], 2) # RAIM标志 (1 bit)
# pos += 1
# comm_state = int(bit_string[pos:pos+19], 2) # 通信状态 (19 bits)