254 lines
9.0 KiB
Python
254 lines
9.0 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
Fins 模拟设备服务器
|
|
提供模拟的 Fins 设备用于测试在线脚本中的 Fins 内置函数
|
|
"""
|
|
|
|
import threading
|
|
import socket
|
|
import struct
|
|
import time
|
|
|
|
print("Fins 模拟设备服务器")
|
|
|
|
|
|
class MockFinsServer:
|
|
"""模拟 Fins 服务器用于测试"""
|
|
|
|
def __init__(self, host='127.0.0.1', port=9600):
|
|
self.host = host
|
|
self.port = port
|
|
self.server_socket = None
|
|
self.running = False
|
|
self.thread = None
|
|
|
|
# 模拟数据存储
|
|
self.memory_areas = {
|
|
0x82: { # DM 区域
|
|
100: { # 地址 100
|
|
'word': 1234, # word 数据
|
|
'bits': [True, False, True, False, True, False, True, False], # 8个位
|
|
'string': "HELLO WORLD" # 字符串数据
|
|
},
|
|
200: { # 地址 200
|
|
'word': 5678,
|
|
'bits': [False, True, False, True, False, True, False, True],
|
|
'string': "TEST DATA"
|
|
}
|
|
}
|
|
}
|
|
|
|
def start(self):
|
|
"""启动模拟服务器"""
|
|
try:
|
|
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
self.server_socket.bind((self.host, self.port))
|
|
self.server_socket.listen(5)
|
|
self.running = True
|
|
|
|
self.thread = threading.Thread(target=self._server_loop)
|
|
self.thread.daemon = True
|
|
self.thread.start()
|
|
|
|
print(f"🟢 模拟 Fins 服务器已启动:{self.host}:{self.port}")
|
|
print(f"📊 模拟数据:")
|
|
print(f" - 地址 100: word=1234, bits=[T,F,T,F,T,F,T,F], string='HELLO WORLD'")
|
|
print(f" - 地址 200: word=5678, bits=[F,T,F,T,F,T,F,T], string='TEST DATA'")
|
|
time.sleep(0.1) # 等待服务器完全启动
|
|
|
|
except Exception as e:
|
|
print(f"❌ 启动模拟 Fins 服务器失败: {str(e)}")
|
|
raise
|
|
|
|
def stop(self):
|
|
"""停止模拟服务器"""
|
|
self.running = False
|
|
if self.server_socket:
|
|
self.server_socket.close()
|
|
if self.thread:
|
|
self.thread.join(timeout=1.0)
|
|
print("🔴 模拟 Fins 服务器已停止")
|
|
|
|
def _server_loop(self):
|
|
"""服务器主循环"""
|
|
while self.running:
|
|
try:
|
|
client_socket, addr = self.server_socket.accept()
|
|
print(f"📞 客户端连接: {addr}")
|
|
|
|
# 处理客户端请求
|
|
self._handle_client(client_socket)
|
|
|
|
except Exception as e:
|
|
if self.running:
|
|
print(f"❌ 服务器循环错误: {str(e)}")
|
|
break
|
|
|
|
def _handle_client(self, client_socket):
|
|
"""处理客户端请求"""
|
|
try:
|
|
# 接收请求
|
|
data = client_socket.recv(1024)
|
|
if not data:
|
|
return
|
|
|
|
print(f"📨 收到请求数据: {data.hex()}")
|
|
|
|
# 解析并响应
|
|
response = self._process_fins_request(data)
|
|
|
|
if response:
|
|
client_socket.send(response)
|
|
print(f"📤 发送响应数据: {response.hex()}")
|
|
|
|
except Exception as e:
|
|
print(f"❌ 处理客户端请求失败: {str(e)}")
|
|
finally:
|
|
client_socket.close()
|
|
|
|
def _process_fins_request(self, request_data):
|
|
"""处理 Fins 请求并生成响应"""
|
|
try:
|
|
# 简化的 Fins 协议解析
|
|
if len(request_data) < 28:
|
|
return None
|
|
|
|
# 跳过 TCP 头部,解析 Fins 命令
|
|
fins_start = 16 # 跳过 FINS TCP 头部
|
|
|
|
# 提取命令码
|
|
cmd = struct.unpack('>H', request_data[fins_start + 10:fins_start + 12])[0]
|
|
area = request_data[fins_start + 12]
|
|
addr_high = request_data[fins_start + 13]
|
|
addr_low = request_data[fins_start + 14]
|
|
bit_offset = request_data[fins_start + 15]
|
|
|
|
address = (addr_high << 8) | addr_low
|
|
|
|
print(f"🔍 解析命令: CMD=0x{cmd:04X}, Area=0x{area:02X}, Addr={address}, Bit={bit_offset}")
|
|
|
|
# 生成响应
|
|
if cmd == 0x0101: # 读取命令
|
|
return self._create_read_response(area, address, bit_offset, request_data)
|
|
elif cmd == 0x0102: # 写入命令
|
|
return self._create_write_response(area, address, bit_offset, request_data)
|
|
|
|
except Exception as e:
|
|
print(f"❌ 处理 Fins 请求失败: {str(e)}")
|
|
return None
|
|
|
|
def _create_read_response(self, area, address, bit_offset, request_data):
|
|
"""创建读取响应"""
|
|
try:
|
|
# 构造响应头部
|
|
response_header = b'FINS' + b'\x00' * 12
|
|
|
|
# Fins 响应头部(复制请求头部并修改)
|
|
fins_header = request_data[16:26] # 复制原始头部
|
|
|
|
# 添加响应码 (成功)
|
|
response_code = struct.pack('>H', 0x0000)
|
|
|
|
# 获取模拟数据
|
|
if area in self.memory_areas and address in self.memory_areas[area]:
|
|
area_data = self.memory_areas[area][address]
|
|
|
|
# 根据请求类型返回不同数据
|
|
if bit_offset == 0: # Word 读取
|
|
word_data = struct.pack('>H', area_data['word'])
|
|
data_part = word_data
|
|
else: # Bit 读取
|
|
bit_value = 1 if area_data['bits'][bit_offset] else 0
|
|
data_part = struct.pack('B', bit_value)
|
|
else:
|
|
# 返回默认数据
|
|
data_part = b'\x00\x00'
|
|
|
|
# 组装完整响应
|
|
fins_response = fins_header + response_code + data_part
|
|
|
|
# 更新长度
|
|
length = len(fins_response)
|
|
response_header = response_header[:8] + struct.pack('>I', length) + response_header[12:]
|
|
|
|
return response_header + fins_response
|
|
|
|
except Exception as e:
|
|
print(f"❌ 创建读取响应失败: {str(e)}")
|
|
return None
|
|
|
|
def _create_write_response(self, area, address, bit_offset, request_data):
|
|
"""创建写入响应"""
|
|
try:
|
|
# 模拟写入操作
|
|
print(f"✏️ 模拟写入: Area=0x{area:02X}, Addr={address}, Bit={bit_offset}")
|
|
|
|
# 构造简单的成功响应
|
|
response_header = b'FINS' + b'\x00' * 12
|
|
fins_header = request_data[16:26]
|
|
response_code = struct.pack('>H', 0x0000) # 成功
|
|
|
|
fins_response = fins_header + response_code
|
|
|
|
# 更新长度
|
|
length = len(fins_response)
|
|
response_header = response_header[:8] + struct.pack('>I', length) + response_header[12:]
|
|
|
|
return response_header + fins_response
|
|
|
|
except Exception as e:
|
|
print(f"❌ 创建写入响应失败: {str(e)}")
|
|
return None
|
|
|
|
|
|
def start_mock_fins_server():
|
|
"""启动模拟 Fins 服务器"""
|
|
server = MockFinsServer('127.0.0.1', 9600)
|
|
server.start()
|
|
return server
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("🚀 启动 Fins 模拟设备服务器")
|
|
print("=" * 50)
|
|
|
|
try:
|
|
# 启动模拟服务器
|
|
server = start_mock_fins_server()
|
|
|
|
print("\n📋 测试说明:")
|
|
print(" 可以在在线脚本中使用以下代码测试:")
|
|
print("")
|
|
print(" # 测试读取 word")
|
|
print(" result = VWED.fins.read_fins_word('127.0.0.1', 9600, 0x82, 100, 0)")
|
|
print(" print(f'读取 word 结果: {result}') # 期望: 1234")
|
|
print("")
|
|
print(" # 测试读取 bit")
|
|
print(" result = VWED.fins.read_fins_bit('127.0.0.1', 9600, 0x82, 100, 0)")
|
|
print(" print(f'读取 bit 结果: {result}') # 期望: 1 (True)")
|
|
print("")
|
|
print(" # 测试写入 word")
|
|
print(" VWED.fins.write_fins_word('127.0.0.1', 9600, 0x82, 200, 0, 9999)")
|
|
print(" print('写入 word 完成')")
|
|
print("")
|
|
print(" # 测试写入 bit")
|
|
print(" VWED.fins.write_fins_bit('127.0.0.1', 9600, 0x82, 200, 3, True)")
|
|
print(" print('写入 bit 完成')")
|
|
print("")
|
|
print("💡 按 Ctrl+C 停止服务器")
|
|
|
|
# 保持服务器运行
|
|
while True:
|
|
time.sleep(1)
|
|
|
|
except KeyboardInterrupt:
|
|
print("\n⏹️ 收到停止信号")
|
|
except Exception as e:
|
|
print(f"\n❌ 服务器运行失败: {str(e)}")
|
|
finally:
|
|
if 'server' in locals():
|
|
server.stop()
|
|
print("👋 再见!") |