253 lines
10 KiB
Python
253 lines
10 KiB
Python
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()
|