354 lines
14 KiB
Python
354 lines
14 KiB
Python
import socket
|
||
import threading
|
||
import queue
|
||
import random
|
||
import struct
|
||
import time
|
||
import math
|
||
from datetime import datetime
|
||
|
||
# 全局配置
|
||
HOST = 'localhost'
|
||
PORT = 10
|
||
BUFFER_SIZE = 32768
|
||
FRAME_HEADER = b'####'
|
||
|
||
# 长江入海口位置 (中心点)
|
||
YANGTZE_ESTUARY_LAT = 31.23
|
||
YANGTZE_ESTUARY_LON = 121.47
|
||
RANGE_NM = 5 # 5海里范围
|
||
|
||
# 预生成10艘船的MMSI
|
||
SHIP_MMSIS = [random.randint(200000000, 299999999) for _ in range(10)]
|
||
|
||
# 报文类型定义
|
||
MSG_TYPE_DEBUG = 0
|
||
MSG_TYPE_LVDS = 1
|
||
MSG_TYPE_CAN = 2
|
||
MSG_TYPE_AD9361 = 3
|
||
MSG_TYPE_WAVE_CTRL = 4
|
||
MSG_TYPE_TEST_PARAM = 5
|
||
MSG_TYPE_TEST_WAVE = 6
|
||
MSG_TYPE_GPS = 7
|
||
MSG_TYPE_STATUS = 8
|
||
MSG_TYPE_VDES_CTRL = 9
|
||
MSG_TYPE_VDES_UPLOAD = 10
|
||
MSG_TYPE_COLLECT = 11
|
||
MSG_TYPE_DEMOD = 12
|
||
MSG_TYPE_NOTIFY = 13
|
||
|
||
# 解调器类型
|
||
DEMOD_VDES = 0 # VDES解调器 (0-3)
|
||
DEMOD_AIS = 4 # AIS解调器 (4-5)
|
||
|
||
# 通信状态定义 (Annex 2 Table 18)
|
||
COMM_STATES = [
|
||
{"sync_state": 0, "slot_timeout": 0, "sub_message": 0},
|
||
{"sync_state": 1, "slot_timeout": 1, "sub_message": 1},
|
||
{"sync_state": 2, "slot_timeout": 2, "sub_message": 2},
|
||
{"sync_state": 3, "slot_timeout": 3, "sub_message": 3}
|
||
]
|
||
|
||
class VDESTCPServer:
|
||
def __init__(self):
|
||
self.send_queue = queue.Queue()
|
||
self.running = True
|
||
self.device_state = {
|
||
"cpu0": 50,
|
||
"cpu1": 50,
|
||
"version": 0x01020304,
|
||
"uptime": int(time.time()),
|
||
"gps_status": 1,
|
||
"pps_lock": 1,
|
||
"ad9361_status": 2
|
||
}
|
||
self.gps_params = self.generate_gps_data()
|
||
|
||
def start(self):
|
||
# server_thread = threading.Thread(target=self.run_server)
|
||
# server_thread.daemon = True
|
||
# server_thread.start()
|
||
|
||
# send_thread = threading.Thread(target=self.send_data_thread)
|
||
# send_thread.daemon = True
|
||
# send_thread.start()
|
||
|
||
# server_thread.join()
|
||
# send_thread.join()
|
||
print(11111111111)
|
||
print(self.build_gps_message())
|
||
|
||
def run_server(self):
|
||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||
s.bind((HOST, PORT))
|
||
s.listen()
|
||
print(f"VDES TCP Server listening on {HOST}:{PORT}")
|
||
|
||
while self.running:
|
||
conn, addr = s.accept()
|
||
print(f"Connected by {addr}")
|
||
client_thread = threading.Thread(target=self.handle_client, args=(conn,))
|
||
client_thread.daemon = True
|
||
client_thread.start()
|
||
|
||
def handle_client(self, conn):
|
||
with conn:
|
||
while self.running:
|
||
try:
|
||
data = conn.recv(BUFFER_SIZE)
|
||
if not data:
|
||
break
|
||
|
||
# 解析报文
|
||
if len(data) < 12:
|
||
print("Invalid packet size")
|
||
continue
|
||
|
||
header = data[:4]
|
||
if header != FRAME_HEADER:
|
||
print("Invalid frame header")
|
||
continue
|
||
|
||
msg_type = struct.unpack('>I', data[4:8])[0]
|
||
msg_len = struct.unpack('>I', data[8:12])[0]
|
||
msg_content = data[12:12+msg_len] if msg_len > 0 else b''
|
||
|
||
print(f"Received message type: {msg_type}, length: {msg_len}")
|
||
|
||
# 处理报文并准备响应
|
||
response = self.process_message(msg_type, msg_content)
|
||
if response:
|
||
self.send_queue.put(response)
|
||
|
||
except Exception as e:
|
||
print(f"Error handling client: {e}")
|
||
break
|
||
|
||
def process_message(self, msg_type, content):
|
||
"""处理接收到的报文并返回响应"""
|
||
response = None
|
||
|
||
if msg_type == MSG_TYPE_DEBUG:
|
||
# 调试指令报文
|
||
if len(content) >= 1:
|
||
cmd_type = content[0]
|
||
print(f"Received debug command: {cmd_type}")
|
||
# 简单响应通知报文
|
||
response = self.build_notify_message(0, "Debug command processed")
|
||
|
||
elif msg_type == MSG_TYPE_AD9361:
|
||
# AD9361参数控制
|
||
print("Received AD9361 control params")
|
||
response = self.build_notify_message(0, "AD9361 params updated")
|
||
|
||
elif msg_type == MSG_TYPE_TEST_PARAM:
|
||
# 发送测试参数控制
|
||
if len(content) >= 9:
|
||
test_type, test_count, test_interval = struct.unpack('>BII', content[:9])
|
||
print(f"Test params: type={test_type}, count={test_count}, interval={test_interval}ms")
|
||
response = self.build_notify_message(0, "Test params accepted")
|
||
|
||
elif msg_type == MSG_TYPE_VDES_CTRL:
|
||
# VDES协议参数控制
|
||
print("Received VDES control params")
|
||
response = self.build_notify_message(0, "VDES params updated")
|
||
|
||
elif msg_type == MSG_TYPE_VDES_UPLOAD:
|
||
# VDES上注数据
|
||
if len(content) >= 1:
|
||
data_type = content[0]
|
||
print(f"VDES upload data type: {data_type}")
|
||
response = self.build_notify_message(0, "Data upload accepted")
|
||
|
||
return response
|
||
|
||
def send_data_thread(self):
|
||
"""发送线程,定期发送GPS和解调数据报文"""
|
||
while self.running:
|
||
try:
|
||
# 发送GPS数据 (每秒一次)
|
||
self.gps_params = self.generate_gps_data()
|
||
gps_msg = self.build_gps_message()
|
||
self.send_queue.put(gps_msg)
|
||
|
||
# 发送解调数据 (随机间隔)
|
||
if random.random() > 0.7:
|
||
demod_msg = self.build_demod_message()
|
||
self.send_queue.put(demod_msg)
|
||
|
||
# 发送状态监控数据 (每秒一次)
|
||
status_msg = self.build_status_message()
|
||
self.send_queue.put(status_msg)
|
||
|
||
# 发送队列中的响应报文
|
||
while not self.send_queue.empty():
|
||
msg = self.send_queue.get()
|
||
# 在实际服务器中,这里应该发送给所有连接的客户端
|
||
# 本示例中仅打印发送信息
|
||
print(f"Sending message type: {struct.unpack('>I', msg[4:8])[0]}, "
|
||
f"length: {struct.unpack('>I', msg[8:12])[0]}")
|
||
|
||
time.sleep(1)
|
||
|
||
except Exception as e:
|
||
print(f"Error in send thread: {e}")
|
||
|
||
def build_packet(self, msg_type, content):
|
||
"""构建完整TCP报文"""
|
||
header = FRAME_HEADER
|
||
type_field = struct.pack('>I', msg_type)
|
||
length_field = struct.pack('>I', len(content))
|
||
return header + type_field + length_field + content
|
||
|
||
def build_gps_message(self):
|
||
"""构建GPS解析数据报文 (类型7)"""
|
||
content = struct.pack('>QiiihhhBBBBBB',
|
||
self.gps_params["utc_time"],
|
||
self.gps_params["longitude"],
|
||
self.gps_params["latitude"],
|
||
self.gps_params["altitude"],
|
||
self.gps_params["used_sats"],
|
||
self.gps_params["gps_sats"],
|
||
self.gps_params["beidou_sats"],
|
||
self.gps_params["gps_status"],
|
||
self.gps_params["fix_mode"],
|
||
self.gps_params["hdop"],
|
||
self.gps_params["speed"],
|
||
self.gps_params["course"])
|
||
return self.build_packet(MSG_TYPE_GPS, content)
|
||
|
||
def build_demod_message(self):
|
||
"""构建VDES解调数据报文 (类型12)"""
|
||
demod_id = random.randint(0, 5)
|
||
comm_state = random.choice(COMM_STATES)
|
||
|
||
if demod_id <= DEMOD_VDES + 3: # VDES解调器 (0-3)
|
||
# 根据M.2092-1 Annex5 3.10生成消息
|
||
msg_data = self.generate_vdes_message()
|
||
else: # AIS解调器 (4-5)
|
||
# 根据M.1371-5 Annex8 3.1生成Message1
|
||
msg_data = self.generate_ais_message1()
|
||
|
||
# 构建通信状态字段
|
||
comm_state_field = struct.pack('>BBH',
|
||
(comm_state["sync_state"] << 6) | (comm_state["slot_timeout"] << 3),
|
||
comm_state["sub_message"] >> 8,
|
||
comm_state["sub_message"] & 0xFF)
|
||
|
||
# 构建完整报文
|
||
content = struct.pack('>BBHH', 12, demod_id, random.randint(0, 65535), random.randint(0, 65535))
|
||
content += struct.pack('>H', random.randint(-12800, 12700)) # 信噪比
|
||
content += comm_state_field
|
||
content += msg_data
|
||
|
||
return self.build_packet(MSG_TYPE_DEMOD, content)
|
||
|
||
def build_status_message(self):
|
||
"""构建地检状态监控报文 (类型8)"""
|
||
# 更新设备状态
|
||
self.device_state["cpu0"] = random.randint(40, 60)
|
||
self.device_state["cpu1"] = random.randint(40, 60)
|
||
self.device_state["uptime"] = int(time.time())
|
||
|
||
# 构建报文内容 (简化版)
|
||
content = struct.pack('>BBIIBBBB',
|
||
self.device_state["cpu0"],
|
||
self.device_state["cpu1"],
|
||
self.device_state["version"],
|
||
self.device_state["uptime"],
|
||
self.device_state["gps_status"],
|
||
self.device_state["pps_lock"],
|
||
self.device_state["ad9361_status"],
|
||
0) # 校准因子占位
|
||
|
||
return self.build_packet(MSG_TYPE_STATUS, content)
|
||
|
||
def build_notify_message(self, msg_type, text):
|
||
"""构建消息通知报文 (类型13)"""
|
||
text_bytes = text.encode('utf-8')
|
||
content = struct.pack('>B', msg_type) + text_bytes
|
||
return self.build_packet(MSG_TYPE_NOTIFY, content)
|
||
|
||
def generate_gps_data(self):
|
||
"""生成GPS数据 (长江入海口5海里范围内)"""
|
||
# 在中心点附近5海里范围内生成随机位置
|
||
lat, lon = self.generate_random_position()
|
||
|
||
return {
|
||
"utc_time": int(time.time()),
|
||
"longitude": int(lon * 10000000),
|
||
"latitude": int(lat * 10000000),
|
||
"altitude": random.randint(-50, 100),
|
||
"used_sats": random.randint(5, 12),
|
||
"gps_sats": random.randint(3, 8),
|
||
"beidou_sats": random.randint(3, 8),
|
||
"gps_status": random.randint(0, 4),
|
||
"fix_mode": random.randint(1, 3),
|
||
"hdop": random.randint(10, 100),
|
||
"speed": random.randint(0, 2000), # 0.01节单位
|
||
"course": random.randint(0, 35900) # 0.01度单位
|
||
}
|
||
|
||
def generate_random_position(self):
|
||
"""在长江入海口5海里范围内生成随机位置"""
|
||
# 1海里 ≈ 0.0166667度 (赤道附近)
|
||
offset_lat = (random.random() - 0.5) * RANGE_NM * 0.0166667
|
||
offset_lon = (random.random() - 0.5) * RANGE_NM * 0.0166667
|
||
|
||
lat = YANGTZE_ESTUARY_LAT + offset_lat
|
||
lon = YANGTZE_ESTUARY_LON + offset_lon
|
||
|
||
return lat, lon
|
||
|
||
def generate_vdes_message(self):
|
||
"""生成VDES消息 (M.2092-1 Annex5 3.10)"""
|
||
# 随机选择一种消息类型 (简化实现)
|
||
msg_types = [0, 1, 2, 3, 4, 5]
|
||
msg_type = random.choice(msg_types)
|
||
|
||
# 构建基本消息结构
|
||
msg = struct.pack('>B', msg_type)
|
||
|
||
# 添加随机内容
|
||
if msg_type == 0: # Paging
|
||
msg += struct.pack('>I', random.randint(100000000, 999999999))
|
||
elif msg_type == 1: # Resource request
|
||
msg += struct.pack('>IB', random.randint(100000000, 999999999), random.randint(0, 255))
|
||
|
||
return msg
|
||
|
||
def generate_ais_message1(self):
|
||
"""生成AIS Message1位置报告 (M.1371-5 Annex8 3.1)"""
|
||
# 随机位置
|
||
lat, lon = self.generate_random_position()
|
||
|
||
# 转换为AIS格式
|
||
lat_ais = int((lat + 90) * 60000)
|
||
lon_ais = int((lon + 180) * 60000)
|
||
|
||
# 随机选择一艘船
|
||
mmsi = random.choice(SHIP_MMSIS)
|
||
|
||
# 随机通信状态
|
||
comm_state = random.choice(COMM_STATES)
|
||
comm_state_field = (
|
||
(comm_state["sync_state"] << 17) |
|
||
(comm_state["slot_timeout"] << 14) |
|
||
comm_state["sub_message"]
|
||
)
|
||
|
||
# 构建Message1 (168位/21字节)
|
||
msg = struct.pack('>I', (1 << 26) | (random.randint(0, 3) << 24) | (mmsi >> 6))
|
||
msg += struct.pack('>I', ((mmsi & 0x3F) << 26) | (random.randint(0, 15) << 22))
|
||
msg += struct.pack('>I', (random.randint(0, 255) << 24) | (random.randint(0, 1023) << 14))
|
||
msg += struct.pack('>I', (random.randint(0, 1) << 31) | (lon_ais & 0xFFFFFFF))
|
||
msg += struct.pack('>I', (lat_ais << 4) | (random.randint(0, 4095) >> 8))
|
||
msg += struct.pack('>I', ((random.randint(0, 4095) & 0xFF) << 24) | (random.randint(0, 3599) << 12))
|
||
msg += struct.pack('>I', (random.randint(0, 511) << 23) | (random.randint(0, 63) << 17) | (comm_state_field & 0x1FFFF))
|
||
|
||
return msg
|
||
|
||
if __name__ == "__main__":
|
||
server = VDESTCPServer()
|
||
server.start()
|