import struct import time import os from datetime import datetime from django.core.cache import cache class VdesDemodData: def __init__(self): self.hello = "VDES/AIS解调数据解析工具类" # 存储会话数据,key是 (source_id, satellite_id, session_id, dest_id) # value = {"fragments": [...], "total": N} self.sessions = {} self.payload_fragments = [] # 用于存储长消息分片数据的数组 def main(self, demod_data, file_name=None): self.file_name = file_name 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) print(message_fragment) # 处理消息片段 # self.message_fragment_processing(message_fragment) elif demod_data_type == 1: sbb1 = self.get_sbb_fragment_data_1(demod_data) print(sbb1) cache.set("sbb1", sbb1, timeout=None) #存入redis缓存中,让另一个进程能获取 elif demod_data_type == 2: sbb2 = self.get_sbb_fragment_data_2(demod_data) print(sbb2) cache.set("sbb2", sbb2, timeout=None) elif demod_data_type == 3: sbb3 = self.get_sbb_fragment_data_3(demod_data) print(sbb3) cache.set("sbb3", sbb3, timeout=None) elif demod_data_type == 4: sbb4 = self.get_sbb_fragment_data_4(demod_data) print(sbb4) cache.set("sbb4", sbb4, timeout=None) elif demod_data_type == 5: sbb5 = self.get_sbb_fragment_data_5(demod_data) print(sbb5) cache.set("sbb5", sbb5, timeout=None) elif demod_data_type == 6: sbb6 = self.get_sbb_fragment_data_6(demod_data) print(sbb6) cache.set("sbb6", sbb6, timeout=None) 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) # 提取payload(减去12字节帧尾) payload = packed_data[header_size:header_size + payload_size - 12] # 尝试解码为字符串,否则保留二进制 # try: # decoded_payload = payload.decode('utf-8') # except UnicodeDecodeError: # decoded_payload = payload session_key = (source_id, satellite_id, session_id, dest_id) # ---------- Type = 30 会话开始 ---------- if Type == 30: total_fragments = remainder_fragment_num + 1 self.sessions[session_key] = { "fragments": [None] * total_fragments, "total": total_fragments, "end_flag": False, "end_time": None } # 起始片段必然是索引 0 self.sessions[session_key]["fragments"][0] = payload # 如果 remainder_fragment_num=0,说明只有这一个片段 if remainder_fragment_num == 0: return self.finalize_session(session_key) # ---------- Type = 31 会话延续 ---------- elif Type == 31: if session_key not in self.sessions: raise ValueError(f"收到延续片段但会话未初始化: {session_key}") session = self.sessions[session_key] index = remainder_fragment_num # 延续片段索引 = remainder_fragment_num session["fragments"][index] = payload # ---------- Type = 32 会话结束 ---------- elif Type == 32: if session_key not in self.sessions: raise ValueError(f"收到结束片段但会话未初始化: {session_key}") session = self.sessions[session_key] index = remainder_fragment_num # 结束片段索引 = remainder_fragment_num session["fragments"][index] = payload session["end_flag"] = True session["end_time"] = time.time() # 如果所有片段收齐,立刻完成 if all(frag is not None for frag in session["fragments"]): return self.finalize_session(session_key, force=True) # 检查超时的会话 self.check_timeouts() 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': payload } def check_timeouts(self): """检查会话是否超时 40 秒""" now = time.time() to_release = [] for key, session in self.sessions.items(): if session["end_flag"] and session["end_time"]: if now - session["end_time"] > 40: to_release.append(key) for key in to_release: print(f"会话 {key} 超时未收齐,强制释放") self.finalize_session(key, force=True) def finalize_session(self, session_key, force=False): """拼接并释放一个会话""" session = self.sessions[session_key] full_data = b"" mmsi = session_key[0] #source_id为MMSI号 for frag in session["fragments"]: if frag is None and not force: # 不完整且不强制 → 暂不释放 return None if frag: full_data += frag # if isinstance(frag, str): # full_data += frag.encode("utf-8") # elif isinstance(frag, bytes): # full_data += frag if full_data is not None: # 保存为图片文件 self.message_fragment_processing(full_data, mmsi) del self.sessions[session_key] print(f"✅ 会话 {session_key} 完成, 数据长度={len(full_data)}") return {"Session_key": session_key, "Full_data": full_data} def message_fragment_processing(self, message, mmsi): from system.models import HistorySession, Contacts, Content, MessageFlag # 此处需要判断接收的消息数据格式---------------------------------------- if message is not None: print('-------------------------------------------') # print("完整消息:", combined_data) # 创建保存目录(如果不存在) - 使用Django静态资源路径 save_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'static', 'vdes_data') os.makedirs(save_dir, exist_ok=True) # 生成文件名(带时间戳) - 使用self.file_name作为后缀名 timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') file_extension = getattr(self, 'file_name', 'jpg') # 默认使用txt作为后缀名 if file_extension is None: file_extension = 'jpg' print(f"文件后缀名: {file_extension}") # 根据文件后缀判断文件类型 file_type = self.get_file_type(file_extension) if file_type == 0: try: # 直接解码消息内容 if isinstance(message, bytes): content_text = message.decode('utf-8') else: content_text = str(message) except Exception as e: print(f"保存数据库记录时出错: {e}") content_text = '无法解码的文本内容' content = "
"+content_text+"
" else: filename = os.path.join(save_dir, f'received_file_{timestamp}.{file_extension}') # 写入文件 with open(filename, 'wb') as f: f.write(message) print(f"文件已保存到: {filename}") print(f"发送者MMSI: {mmsi}") # 构建文件的相对URL路径(相对于Django服务器) content = f"/static/vdes_data/received_file_{timestamp}.{file_extension}" # 将文件路径存入数据库------------------------------------------------------ try: # 查询或创建通讯录记录 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 = Content.objects.create( SendId=Id, ReciverId=1, Content=content, # 保存文件路径或文本内容 Type=file_type, # 2=文件类型 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() print(f"文件路径已保存到数据库: {filename}") except Exception as e: print(f"保存数据库记录时出错: {e}") 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=""+combined_data+"
", 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 get_file_type(self, file_extension): """ 根据文件后缀判断文件类型 :param file_extension: 文件后缀 :return: 文件类型 (0: txt, 1: 图片, 2: 视频) """ # 文本文件 if file_extension.lower() in ['txt']: return 0 # 图片文件 if file_extension.lower() in ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']: return 1 # 视频文件 if file_extension.lower() in ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv']: return 2 # 默认返回二进制文件类型 return 0 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].hex() # 数字签名第1部分(16进制字符串格式) # 去除帧尾数据,只返回解析后的数据 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].hex() # 数字签名第2部分(16进制字符串格式) # 去除帧尾数据,只返回解析后的数据 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