Files
VDES_Backend/code/vdes_utils/vdes_demod_data_bk.py
2026-07-13 15:37:05 +08:00

571 lines
25 KiB
Python
Raw Permalink 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
class VdesDemodData:
def __init__(self):
self.hello = "VDES/AIS解调数据解析工具类"
self.payload_fragments = [] # 用于存储长消息分片数据的数组
def main(self, demod_data):
demod_data_type = self.get_data_type(demod_data)
# print('demod_data_type:', demod_data_type)
# 判断解调数据是什么类型,类型有卫星公告牌、消息片段等
if demod_data_type == 30 or demod_data_type == 31 or demod_data_type == 32:
# 解析出消息片段中的字段
message_fragment = self.get_message_demod_data(demod_data)
# 处理消息片段
self.message_fragment_processing(message_fragment)
# elif demod_data_type == 1:
# sbb1 = self.get_sbb_fragment_data_1(demod_data)
# print(sbb1)
# elif demod_data_type == 2:
# sbb2 = self.get_sbb_fragment_data_2(demod_data)
# print(sbb2)
# elif demod_data_type == 3:
# sbb3 = self.get_sbb_fragment_data_3(demod_data)
# print(sbb3)
# elif demod_data_type == 4:
# sbb4 = self.get_sbb_fragment_data_4(demod_data)
# print(sbb4)
# elif demod_data_type == 5:
# sbb5 = self.get_sbb_fragment_data_5(demod_data)
# print(sbb5)
# elif demod_data_type == 6:
# sbb6 = self.get_sbb_fragment_data_6(demod_data)
# print(sbb6)
# elif demod_data_type == 10:
# sbb10 = self.get_sbb_fragment_data_10(demod_data)
# print(sbb10)
# elif demod_data_type == 11:
# sbb11 = self.get_sbb_fragment_data_11(demod_data)
# print(sbb11)
# elif demod_data_type == 12:
# sbb12 = self.get_sbb_fragment_data_12(demod_data)
# print(sbb12)
# elif demod_data_type == 18:
# sbb18 = self.get_sbb_fragment_data_18(demod_data)
# print(sbb18)
# elif demod_data_type == 20:
# sbb20 = self.get_sbb_fragment_data_20(demod_data)
# print(sbb20)
def get_data_type(self, demod_data):
"""从二进制数据中提取第一个字节作为类型字段"""
if demod_data:
data_type = struct.unpack('>B', demod_data[:1])[0]
return data_type
else:
return None
def get_message_demod_data(self, packed_data):
"""解码VDES解调信息字段"""
header_size = struct.calcsize('>B H I B B I H')
header = packed_data[:header_size]
Type, payload_size, source_id, satellite_id, session_id, dest_id, remainder_fragment_num = \
struct.unpack('>B H I B B I H', header)
# 计算负载字节长度进去截取,去除帧尾
print(header_size)
print(payload_size)
payload = packed_data[header_size:header_size+payload_size-12]
print('packed_data:', packed_data.hex())
print('payload:', payload.hex())
# 将UTF-8编码的二进制payload解码为字符串
try:
decoded_payload = payload.decode('utf-8')
except UnicodeDecodeError:
decoded_payload = payload # 如果解码失败,保留原始二进制数据
return {
'Type': Type,
'Payload_size': payload_size,
'Source_id': source_id,
'Satellite_id': satellite_id,
'Session_id': session_id,
'Dest_id': dest_id,
'Remainder_Fragment_num': remainder_fragment_num,
'Payload': decoded_payload # 返回解码后的字符串
}
def message_fragment_processing(self, message_fragment):
combined_data = self.message_fragment_splicing(message_fragment)
# 此处需要判断接收的消息数据格式----------------------------------------
if combined_data is not None:
# print("完整消息:", combined_data)
# 保存为图片文件
import os
from datetime import datetime
# 创建保存目录(如果不存在)
save_dir = 'E:\projects\wxwx\projects_job\VDES_Projects\报文模拟解析\地检设备模拟\\tcp_data'
os.makedirs(save_dir, exist_ok=True)
# 生成文件名(带时间戳)
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
filename = os.path.join(save_dir, f'received_image_{timestamp}.jpg') # 假设是JPEG格式
# 写入文件
with open(filename, 'wb') as f:
f.write(combined_data)
print(f"图片已保存到: {filename}")
return
if combined_data is not None:
MMSI = demod_data['Dest_id']
print(f"发送者MMSI: {MMSI}")
print(f"消息: {combined_data}")
# 查询或创建通讯录记录
contact, created = Contacts.objects.get_or_create(MMSI=MMSI)
Id = contact.Id
contact, created = HistorySession.objects.get_or_create(FormId=Id, MMSI=MMSI)
content = Content.objects.create(
SendId=Id,
ReciverId=1,
Content="<p>"+combined_data+"</p>",
Type=0, # 0=html文本
State=1, # 已发送
NoCode=str(int(time.time())) , # 你可以放时间戳
CreateDateUtc=datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
ReadFlag=0,
SoundStatus=0
)
flag = MessageFlag.objects.first()
if flag:
flag.has_new_message = True
flag.save()
def message_fragment_splicing(self, demod_data):
"""拼接消息分片数据"""
fragment_num = demod_data['Fragment_num']
# print(self.payload_fragments)
if demod_data['Type'] == 30: # 开始分片
print("------------------开始——————————————————————————————————————————————")
self.payload_fragments = [] # 清空数组
self.payload_fragments.append(demod_data['Payload'])
elif demod_data['Type'] == 31: # 数据分片
self.payload_fragments.append(demod_data['Payload'])
elif demod_data['Type'] == 32: # 结束分片
# 拼接所有有效分片
print("------------------结束——————————————————————————————————————————————")
self.payload_fragments.append(demod_data['Payload'])
combined_payload = b''.join([p for p in self.payload_fragments if p is not None])
print(len(self.payload_fragments))
return combined_payload
return None # 如果不是结束分片返回None
def get_sbb_fragment_data_1(self, demod_data):
"""解析类型为1的公告牌起始片段数据"""
format_str = '>B B B B H I H B H H B H' # 总共20字节
# 解包数据
fields = struct.unpack(format_str, demod_data[:20])
# 创建结果字典
res = {}
res['type'] = fields[0] # 类型
res['satellite_id'] = fields[1] # 卫星ID
res['primary_network_id'] = fields[2] # 主网络ID
res['roaming_network_id'] = fields[3] # 漫游网络ID
res['sbb_version'] = fields[4] # SBB版本
res['start_time'] = fields[5] # 开始时间
res['validity_period'] = fields[6] # 可用期限
# 解析服务能力字段
capability_field = fields[7] #服务能力
res['itu_compatibility'] = (capability_field >> 4) & 0x0F # ITU-R M.2092建议书版兼容
res['reserved_bits'] = capability_field & 0x0F # 4个LSB保留位
res['sbb_spare_frequency'] = fields[8] # SBB备用频率
res['uplink_max_length'] = fields[9] # 上行链路消息最大长度
res['reserved'] = fields[10] # 保留字段
res['total_message_length'] = fields[11] # 消息总长度
# 去除帧尾数据,只返回解析后的数据
return res
def get_sbb_fragment_data_2(self, demod_data):
"""解析类型为2的公告牌片段数据"""
format_str = '>B H H B 6B 6B H H B 6B 6B' # 总共35字节
# 解包数据
fields = struct.unpack(format_str, demod_data[:35])
# 创建结果字典
res = {}
res['type'] = fields[0] # 类型
res['downlink_frequency_a'] = fields[1] # 下行链路中心频率A
res['uplink_frequency_a'] = fields[2] # 上行链路中心频率A
# 解析带宽A字段
bandwidth_a = fields[3]
res['downlink_bandwidth_a'] = (bandwidth_a >> 4) & 0x0F # 下行链路带宽A
res['uplink_bandwidth_a'] = bandwidth_a & 0x0F # 上行链路带宽A
channel_slot_lengths_a = []
for i in range(4, 10): # 6个字节
byte_val = fields[i]
# 高4位和低4位分别代表两个信道的时隙长度
high_nibble = (byte_val >> 4) & 0x0F
low_nibble = byte_val & 0x0F
channel_slot_lengths_a.extend([high_nibble, low_nibble])
res['channel_slot_lengths_a'] = channel_slot_lengths_a
# 解析逻辑信道功能A (6字节表示12个信道每个信道4比特)
channel_functions_a = []
for i in range(10, 16): # 6个字节
byte_val = fields[i]
# 高4位和低4位分别代表两个信道的功能
high_nibble = (byte_val >> 4) & 0x0F
low_nibble = byte_val & 0x0F
channel_functions_a.extend([high_nibble, low_nibble])
res['channel_functions_a'] = channel_functions_a
res['downlink_frequency_b'] = fields[16] # 下行链路中心频率B
res['uplink_frequency_b'] = fields[17] # 上行链路中心频率B
# 解析带宽B字段
bandwidth_b = fields[18]
res['downlink_bandwidth_b'] = (bandwidth_b >> 4) & 0x0F # 下行链路带宽B
res['uplink_bandwidth_b'] = bandwidth_b & 0x0F # 上行链路带宽B
# 解析逻辑信道时隙长度B (6字节表示12个信道每个信道4比特)
channel_slot_lengths_b = []
for i in range(19, 25): # 6个字节
byte_val = fields[i]
# 高4位和低4位分别代表两个信道的时隙长度
high_nibble = (byte_val >> 4) & 0x0F
low_nibble = byte_val & 0x0F
channel_slot_lengths_b.extend([high_nibble, low_nibble])
res['channel_slot_lengths_b'] = channel_slot_lengths_b
# 解析逻辑信道功能B (6字节表示12个信道每个信道4比特)
channel_functions_b = []
for i in range(25, 31): # 6个字节
byte_val = fields[i]
# 高4位和低4位分别代表两个信道的功能
high_nibble = (byte_val >> 4) & 0x0F
low_nibble = byte_val & 0x0F
channel_functions_b.extend([high_nibble, low_nibble])
res['channel_functions_b'] = channel_functions_b
# 去除帧尾数据,只返回解析后的数据
return res
def get_sbb_fragment_data_3(self, demod_data):
"""解析类型为3的公告牌片段数据逻辑信道24-47定义频率对C和D"""
format_str = '>B H H B 6B 6B H H B 6B 6B' # 总共35字节
# 解包数据
fields = struct.unpack(format_str, demod_data[:35])
# 创建结果字典
res = {}
res['type'] = fields[0] # 类型
res['downlink_frequency_c'] = fields[1] # 下行链路中心频率C
res['uplink_frequency_c'] = fields[2] # 上行链路中心频率C
# 解析带宽C字段
bandwidth_c = fields[3]
res['downlink_bandwidth_c'] = (bandwidth_c >> 4) & 0x0F # 下行链路带宽C
res['uplink_bandwidth_c'] = bandwidth_c & 0x0F # 上行链路带宽C
# 解析逻辑信道时隙长度C (6字节表示12个信道每个信道4比特)
channel_slot_lengths_c = []
for i in range(4, 10): # 6个字节
byte_val = fields[i]
# 高4位和低4位分别代表两个信道的时隙长度
high_nibble = (byte_val >> 4) & 0x0F
low_nibble = byte_val & 0x0F
channel_slot_lengths_c.extend([high_nibble, low_nibble])
res['channel_slot_lengths_c'] = channel_slot_lengths_c
# 解析逻辑信道功能C (6字节表示12个信道每个信道4比特)
channel_functions_c = []
for i in range(10, 16): # 6个字节
byte_val = fields[i]
# 高4位和低4位分别代表两个信道的功能
high_nibble = (byte_val >> 4) & 0x0F
low_nibble = byte_val & 0x0F
channel_functions_c.extend([high_nibble, low_nibble])
res['channel_functions_c'] = channel_functions_c
res['downlink_frequency_d'] = fields[16] # 下行链路中心频率D
res['uplink_frequency_d'] = fields[17] # 上行链路中心频率D
# 解析带宽D字段
bandwidth_d = fields[18]
res['downlink_bandwidth_d'] = (bandwidth_d >> 4) & 0x0F # 下行链路带宽D
res['uplink_bandwidth_d'] = bandwidth_d & 0x0F # 上行链路带宽D
# 解析逻辑信道时隙长度D (6字节表示12个信道每个信道4比特)
channel_slot_lengths_d = []
for i in range(19, 25): # 6个字节
byte_val = fields[i]
# 高4位和低4位分别代表两个信道的时隙长度
high_nibble = (byte_val >> 4) & 0x0F
low_nibble = byte_val & 0x0F
channel_slot_lengths_d.extend([high_nibble, low_nibble])
res['channel_slot_lengths_d'] = channel_slot_lengths_d
# 解析逻辑信道功能D (6字节表示12个信道每个信道4比特)
channel_functions_d = []
for i in range(25, 31): # 6个字节
byte_val = fields[i]
# 高4位和低4位分别代表两个信道的功能
high_nibble = (byte_val >> 4) & 0x0F
low_nibble = byte_val & 0x0F
channel_functions_d.extend([high_nibble, low_nibble])
res['channel_functions_d'] = channel_functions_d
# 去除帧尾数据,只返回解析后的数据
return res
def get_sbb_fragment_data_4(self, demod_data):
"""解析类型为4的公告牌片段数据逻辑信道48-71定义频率对E和F"""
format_str = '>B H H B 6B 6B H H B 6B 6B' # 总共35字节
# 解包数据
fields = struct.unpack(format_str, demod_data[:35])
# 创建结果字典
res = {}
res['type'] = fields[0] # 类型
res['downlink_frequency_e'] = fields[1] # 下行链路中心频率E
res['uplink_frequency_e'] = fields[2] # 上行链路中心频率E
# 解析带宽E字段
bandwidth_e = fields[3]
res['downlink_bandwidth_e'] = (bandwidth_e >> 4) & 0x0F # 下行链路带宽E
res['uplink_bandwidth_e'] = bandwidth_e & 0x0F # 上行链路带宽E
# 解析逻辑信道时隙长度E (6字节表示12个信道每个信道4比特)
channel_slot_lengths_e = []
for i in range(4, 10): # 6个字节
byte_val = fields[i]
# 高4位和低4位分别代表两个信道的时隙长度
high_nibble = (byte_val >> 4) & 0x0F
low_nibble = byte_val & 0x0F
channel_slot_lengths_e.extend([high_nibble, low_nibble])
res['channel_slot_lengths_e'] = channel_slot_lengths_e
# 解析逻辑信道功能E (6字节表示12个信道每个信道4比特)
channel_functions_e = []
for i in range(10, 16): # 6个字节
byte_val = fields[i]
# 高4位和低4位分别代表两个信道的功能
high_nibble = (byte_val >> 4) & 0x0F
low_nibble = byte_val & 0x0F
channel_functions_e.extend([high_nibble, low_nibble])
res['channel_functions_e'] = channel_functions_e
res['downlink_frequency_f'] = fields[16] # 下行链路中心频率F
res['uplink_frequency_f'] = fields[17] # 上行链路中心频率F
# 解析带宽F字段
bandwidth_f = fields[18]
res['downlink_bandwidth_f'] = (bandwidth_f >> 4) & 0x0F # 下行链路带宽F
res['uplink_bandwidth_f'] = bandwidth_f & 0x0F # 上行链路带宽F
# 解析逻辑信道时隙长度F (6字节表示12个信道每个信道4比特)
channel_slot_lengths_f = []
for i in range(19, 25): # 6个字节
byte_val = fields[i]
# 高4位和低4位分别代表两个信道的时隙长度
high_nibble = (byte_val >> 4) & 0x0F
low_nibble = byte_val & 0x0F
channel_slot_lengths_f.extend([high_nibble, low_nibble])
res['channel_slot_lengths_f'] = channel_slot_lengths_f
# 解析逻辑信道功能F (6字节表示12个信道每个信道4比特)
channel_functions_f = []
for i in range(25, 31): # 6个字节
byte_val = fields[i]
# 高4位和低4位分别代表两个信道的功能
high_nibble = (byte_val >> 4) & 0x0F
low_nibble = byte_val & 0x0F
channel_functions_f.extend([high_nibble, low_nibble])
res['channel_functions_f'] = channel_functions_f
# 去除帧尾数据,只返回解析后的数据
return res
def get_sbb_fragment_data_5(self, demod_data):
"""解析类型为5的公告牌片段数据SBB数字签名第1部分"""
format_str = '>B 32s' # 总共33字节
# 解包数据
fields = struct.unpack(format_str, demod_data[:33])
# 创建结果字典
res = {}
res['type'] = fields[0] # 类型
res['digital_signature_part1'] = fields[1] # 数字签名第1部分
# 去除帧尾数据,只返回解析后的数据
return res
def get_sbb_fragment_data_6(self, demod_data):
"""解析类型为6的公告牌片段数据SBB数字签名第2部分"""
format_str = '>B 32s' # 总共33字节
# 解包数据
fields = struct.unpack(format_str, demod_data[:33])
# 创建结果字典
res = {}
res['type'] = fields[0] # 类型
res['digital_signature_part1'] = fields[1] # 数字签名第2部分
# 去除帧尾数据,只返回解析后的数据
return res
def get_sbb_fragment_data_10(self, demod_data):
"""解析类型为10的媒体访问控制数据"""
format_str = '>B H B B B B B B B B H' # 总共13字节
# 解包数据
fields = struct.unpack(format_str, demod_data[:13])
# 创建结果字典
res = {}
res['type'] = fields[0] # 类型
res['payload_size'] = fields[1] # 载荷大小
res['satellite_id'] = fields[2] # 卫星ID
res['primary_network_id'] = fields[3] # 主网络ID
res['roaming_network_id'] = fields[4] # 漫游网络ID
res['media_access_priority'] = fields[5] # 媒体接入优先级
res['random_selection_interval'] = fields[6] # 随机选择间隔
res['rac_message_access_limit'] = fields[7] # RAC消息接入限制
res['network_status'] = fields[8] # 网络状态
# 解析自动重复请求/超时限制字段
arq_timeout_field = fields[9]
res['fragment_retry_count'] = (arq_timeout_field >> 4) & 0x0F # 4个MSB片段重试次数
res['timeout_timer_setting'] = arq_timeout_field & 0x0F # 4个LSB超时定时器设置
res['announcement_version_number'] = fields[10] # 公告版本号
# 去除帧尾数据,只返回解析后的数据
return res
def get_sbb_fragment_data_11(self, demod_data):
"""解析寻呼数据类型11"""
# 总共35字节 (1+2+4+4+4+4+4+4+4+4)
format_str = '>B H I I I I I I I I'
# 解包数据
fields = struct.unpack(format_str, demod_data[:35])
# 创建结果字典
res = {}
res['type'] = fields[0] # 类型
res['payload_size'] = fields[1] # 载荷大小
res['vessel_station_id_1'] = fields[2] # 1号船舶电台ID
res['vessel_station_id_2'] = fields[3] # 2号船舶电台ID
res['vessel_station_id_3'] = fields[4] # 3号船舶电台ID
res['vessel_station_id_4'] = fields[5] # 4号船舶电台ID
res['vessel_station_id_5'] = fields[6] # 5号船舶电台ID
res['vessel_station_id_6'] = fields[7] # 6号船舶电台ID
res['vessel_station_id_7'] = fields[8] # 7号船舶电台ID
res['vessel_station_id_8'] = fields[9] # 8号船舶电台ID
# 去除帧尾数据,只返回解析后的数据
return res
def get_sbb_fragment_data_12(self, demod_data):
"""解析资源分配数据类型12"""
# 总共37字节 (1+2+4+1+1+1+1 + 4+1+1+1+1 + 4+1+1+1+1 + 4+1+1+1+1)
format_str = '>B H I B B B B I B B B B I B B B B I B B B B'
# 解包数据
fields = struct.unpack(format_str, demod_data[:35])
# 创建结果字典
res = {}
res['type'] = fields[0] # 类型
res['payload_size'] = fields[1] # 载荷大小
res['vessel_station_id_1'] = fields[2] # 船舶电台ID 1
res['logical_channel_1'] = fields[3] # 逻辑信道1
res['link_id_1'] = fields[4] # 链路ID 1
res['session_id_1'] = fields[5] # 会话ID 1
res['uplink_cqi_1'] = fields[6] # 上行链路链路CQI 1
res['vessel_station_id_2'] = fields[7] # 船舶电台ID 2
res['logical_channel_2'] = fields[8] # 逻辑信道2
res['link_id_2'] = fields[9] # 链路ID 2
res['session_id_2'] = fields[10] # 会话ID 2
res['uplink_cqi_2'] = fields[11] # 上行链路链路CQI 2
res['vessel_station_id_3'] = fields[12] # 船舶电台ID 3
res['logical_channel_3'] = fields[13] # 逻辑信道3
res['link_id_3'] = fields[14] # 链路ID 3
res['session_id_3'] = fields[15] # 会话ID 3
res['uplink_cqi_3'] = fields[16] # 上行链路链路CQI 3
res['vessel_station_id_4'] = fields[17] # 船舶电台ID 4
res['logical_channel_4'] = fields[18] # 逻辑信道4
res['link_id_4'] = fields[19] # 链路ID 4
res['session_id_4'] = fields[20] # 会话ID 4
res['uplink_cqi_4'] = fields[21] # 上行链路链路CQI 4
# 去除帧尾数据,只返回解析后的数据
return res
def get_sbb_fragment_data_18(self, demod_data):
"""解析送达通知数据类型18"""
# 总共34字节 (1+2+1+4+1+4+1+4+1+4+1+4+1+4+1)
format_str = '>B H B I B I B I B I B I B I B'
# 解包数据
fields = struct.unpack(format_str, demod_data[:34])
# 创建结果字典
res = {}
res['type'] = fields[0] # 类型
res['payload_size'] = fields[1] # 载荷大小
res['satellite_id'] = fields[2] # 卫星ID
res['vessel_station_id_1'] = fields[3] # 1号船舶电台ID
res['session_id_1'] = fields[4] # 1号船舶会话ID
res['vessel_station_id_2'] = fields[5] # 2号船舶电台ID
res['session_id_2'] = fields[6] # 2号船舶会话ID
res['vessel_station_id_3'] = fields[7] # 3号船舶电台ID
res['session_id_3'] = fields[8] # 3号船舶会话ID
res['vessel_station_id_4'] = fields[9] # 4号船舶电台ID
res['session_id_4'] = fields[10] # 4号船舶会话ID
res['vessel_station_id_5'] = fields[11] # 5号船舶电台ID
res['session_id_5'] = fields[12] # 5号船舶会话ID
res['vessel_station_id_6'] = fields[13] # 6号船舶电台ID
res['session_id_6'] = fields[14] # 6号船舶会话ID
# 去除帧尾数据,只返回解析后的数据
return res
def get_sbb_fragment_data_20(self, demod_data):
"""解析资源请求数据类型20"""
format_str = '>B I B B B B B' # 总共10字节
# 解包数据
fields = struct.unpack(format_str, demod_data[:10])
# 创建结果字典
res = {}
res['type'] = fields[0] # 类型
res['vessel_station_id'] = fields[1] # 船舶电台ID
res['satellite_id'] = fields[2] # 卫星ID
# 解析优先级和消息长度字段
priority_length_field = fields[3]
res['priority'] = (priority_length_field >> 4) & 0x0F # 比特7-4优先级
res['message_length'] = priority_length_field & 0x0F # 比特3-0消息长度
res['terminal_capability'] = fields[4] # 终端能力
res['downlink_asc_cqi'] = fields[5] # 下行链路ASC CQI
res['tbd'] = fields[6] # TBD
# 去除帧尾数据,只返回解析后的数据
return res