Files
VDES_Backend/协议资料/zhuoyan_model.py
2026-07-13 15:37:05 +08:00

253 lines
10 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 socket
import struct
import random
import time
import threading
from datetime import datetime, timedelta
# 报文类型常量
MSG_DEBUG = 0
MSG_LVDS = 1
MSG_CAN = 2
MSG_AD9361_CTRL = 3
MSG_WAVE_CTRL = 4
MSG_TEST_PARAM_CTRL = 5
MSG_TEST_WAVE_UPLOAD = 6
MSG_GPS = 7
MSG_STATUS_MONITOR = 8
MSG_PROTO_PARAM_CTRL = 9
MSG_DATA_UPLOAD = 10
MSG_DATA_COLLECT = 11
MSG_DEMOD_DATA = 12
MSG_NOTIFICATION = 13
# 解调器编号常量
VDES_DEMOD_RANGE = (0, 3) # VDES解调器编号0-3
AIS_DEMOD_RANGE = (4, 5) # AIS解调器编号4-5
# 长江入海口坐标范围 (31.0°N - 31.5°N, 121.5°E - 122.0°E)
YANGTZE_DELTA_CENTER = (31.23, 121.77) # 上海附近
DELTA_RANGE = 0.05 # ±0.05度 ≈ 5海里
class VDESServer:
def __init__(self, host='localhost', port=10):
self.host = host
self.port = port
self.header = b'####'
self.running = False
self.server_socket = None
self.ship_mmsi = 123456789 # 船舶MMSI
def start(self):
"""启动TCP服务器"""
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.bind((self.host, self.port))
self.server_socket.listen(1)
self.running = True
print(f"VDES Server started on {self.host}:{self.port}")
# 接受客户端连接
client_socket, addr = self.server_socket.accept()
print(f"Connected by {addr}")
# 启动接收线程和定时发送线程
recv_thread = threading.Thread(target=self.handle_client, args=(client_socket,))
send_thread = threading.Thread(target=self.send_periodic_messages, args=(client_socket,))
recv_thread.start()
send_thread.start()
recv_thread.join()
send_thread.join()
def stop(self):
"""停止服务器"""
self.running = False
if self.server_socket:
self.server_socket.close()
def build_packet(self, msg_type, content):
"""构建协议报文:帧头(4) + 类型(4) + 长度(4) + 内容(N)"""
length = len(content)
return self.header + struct.pack('>I', msg_type) + struct.pack('>I', length) + content
def parse_packet(self, data):
"""解析接收到的报文"""
if len(data) < 12 or data[:4] != self.header:
return None, None
msg_type = struct.unpack('>I', data[4:8])[0]
length = struct.unpack('>I', data[8:12])[0]
content = data[12:12+length] if len(data) >= 12 + length else None
return msg_type, content
def handle_debug_command(self, content):
"""处理调试指令报文类型0"""
cmd_type = content[0] if content else 0
responses = {
0: "初始化地检",
1: "测试波形上注完成",
2: "LVDS数据开始上注",
3: "CAN初始化",
4: "LVDS初始化",
5: "AD9361重新校准",
6: "GPS初始化"
}
response_msg = responses.get(cmd_type, "未知指令")
print(f"执行调试指令: {response_msg}")
# 返回通知报文确认
return self.build_packet(MSG_NOTIFICATION, struct.pack('B', 0)) # 类型0: VDES协议开始执行
def handle_client(self, client_socket):
"""处理客户端请求"""
while self.running:
try:
data = client_socket.recv(32768)
if not data:
break
msg_type, content = self.parse_packet(data)
if msg_type is None:
continue
# 根据报文类型处理
if msg_type == MSG_DEBUG:
response = self.handle_debug_command(content)
elif msg_type == MSG_AD9361_CTRL:
response = self.build_packet(MSG_NOTIFICATION, struct.pack('B', 7)) # AD9361状态更新
else:
response = self.build_packet(MSG_NOTIFICATION, struct.pack('B', 3)) # 通用确认
client_socket.send(response)
except Exception as e:
print(f"处理错误: {e}")
break
def send_periodic_messages(self, client_socket):
"""定时发送状态监控和GPS报文"""
while self.running:
try:
# 每秒发送GPS数据类型7
gps_data = self.generate_gps_data()
client_socket.send(self.build_packet(MSG_GPS, gps_data))
# 每秒发送状态监控类型8
status_data = bytes([random.randint(0, 100) for _ in range(50)]) # 随机状态数据
client_socket.send(self.build_packet(MSG_STATUS_MONITOR, status_data))
# 每5秒发送解调数据类型12
if int(time.time()) % 5 == 0:
demod_data = self.generate_demod_data()
client_socket.send(self.build_packet(MSG_DEMOD_DATA, demod_data))
time.sleep(1)
except Exception as e:
print(f"发送错误: {e}")
break
def generate_gps_data(self):
"""生成长江入海口附近的GPS数据"""
# 在长江入海口附近随机生成位置
lat = YANGTZE_DELTA_CENTER[0] + random.uniform(-DELTA_RANGE, DELTA_RANGE)
lon = YANGTZE_DELTA_CENTER[1] + random.uniform(-DELTA_RANGE, DELTA_RANGE)
# 转换为度分格式*10000000
lat_int = int(lat * 10000000)
lon_int = int(lon * 10000000)
# 其他GPS数据字段
utc_time = int((datetime.utcnow() - datetime(1980, 1, 6)).total_seconds())
altitude = random.randint(-10, 50) # 海拔高度(米)
used_satellites = random.randint(5, 12)
gps_satellites = random.randint(4, 8)
beidou_satellites = random.randint(4, 8)
gps_status = random.randint(1, 4) # GPS状态
pos_mode = random.randint(1, 3) # 定位模式
hdop = random.randint(10, 50) # 水平精度因子
speed = random.randint(0, 2000) # 运动速度 (0.01节)
course = random.randint(0, 35900) # 运动方向 (度*100)
# 打包GPS数据
return struct.pack('>Q', utc_time) + \
struct.pack('>i', lon_int) + \
struct.pack('>i', lat_int) + \
struct.pack('>i', altitude) + \
struct.pack('>H', used_satellites) + \
struct.pack('>H', gps_satellites) + \
struct.pack('>H', beidou_satellites) + \
struct.pack('B', gps_status) + \
struct.pack('B', pos_mode) + \
struct.pack('>I', hdop) + \
struct.pack('>I', speed) + \
struct.pack('>I', course)
def generate_demod_data(self):
"""生成解调数据报文类型12"""
demodulator_id = random.randint(0, 5)
msg_type = 12 # 固定值12
satellite_id = random.randint(1, 255)
demod_data = struct.pack('B', msg_type) + struct.pack('B', satellite_id) + struct.pack('B', demodulator_id)
# 根据解调器编号生成数据
if VDES_DEMOD_RANGE[0] <= demodulator_id <= VDES_DEMOD_RANGE[1]:
# VDES解调器 (0-3): 使用M.2092-1 Annex5格式
msg_id = random.choice([10, 11, 12, 20, 21])
content = struct.pack('B', msg_id) + os.urandom(20) # 随机生成20字节数据
else:
# AIS解调器 (4-5): 使用M.1371-5 Annex8 Message1格式
content = self.generate_ais_message1()
return demod_data + content
def generate_ais_message1(self):
"""生成AIS Message 1位置报告"""
# 在长江入海口附近随机生成位置
lat = YANGTZE_DELTA_CENTER[0] + random.uniform(-DELTA_RANGE, DELTA_RANGE)
lon = YANGTZE_DELTA_CENTER[1] + random.uniform(-DELTA_RANGE, DELTA_RANGE)
# 转换为1/10000分钟格式
lat_min = int(lat * 60 * 10000)
lon_min = int(lon * 60 * 10000)
# 其他AIS字段
message_id = 1
repeat_indicator = 0
navigational_status = random.randint(0, 15) # 航行状态
rate_of_turn = random.randint(-128, 127) # 转向率
speed_over_ground = random.randint(0, 1022) # 对地航速 (0.1节)
position_accuracy = 1 # 高精度
course_over_ground = random.randint(0, 3599) # 对地航向 (0.1度)
true_heading = random.randint(0, 359) # 真航向
timestamp = random.randint(0, 59) # UTC秒
maneuver_indicator = random.randint(0, 1) # 操纵指示器
spare = 0
raim_flag = 0 # RAIM标志
# 打包AIS Message 1
return struct.pack('>B', message_id) + \
struct.pack('>B', (repeat_indicator << 6) | (navigational_status << 2) | (rate_of_turn >> 6)) + \
struct.pack('>B', (rate_of_turn & 0x3F) << 2) | (speed_over_ground >> 8) + \
struct.pack('>B', speed_over_ground & 0xFF) + \
struct.pack('>B', (position_accuracy << 7) | (lon_min >> 25)) + \
struct.pack('>B', (lon_min >> 17) & 0xFF) + \
struct.pack('>B', (lon_min >> 9) & 0xFF) + \
struct.pack('>B', (lon_min >> 1) & 0xFF) + \
struct.pack('>B', ((lon_min & 0x1) << 7) | (lat_min >> 20)) + \
struct.pack('>B', (lat_min >> 12) & 0xFF) + \
struct.pack('>B', (lat_min >> 4) & 0xFF) + \
struct.pack('>B', ((lat_min & 0xF) << 4) | (course_over_ground >> 8)) + \
struct.pack('>B', course_over_ground & 0xFF) + \
struct.pack('>H', true_heading) + \
struct.pack('>B', timestamp) + \
struct.pack('>B', (maneuver_indicator << 2) | spare) + \
struct.pack('>B', raim_flag)
if __name__ == "__main__":
server = VDESServer()
try:
server.start()
except PermissionError:
print("错误需要管理员权限绑定到端口10")
except KeyboardInterrupt:
server.stop()