增加了异常信息打印,图像显示增加为原来的两倍大小
This commit is contained in:
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"python-envs.defaultEnvManager": "ms-python.python:conda",
|
||||
"python-envs.defaultPackageManager": "ms-python.python:conda",
|
||||
"python-envs.pythonProjects": []
|
||||
}
|
||||
@@ -52,8 +52,6 @@ CMD_KEEPLIVE, CMD_INIT, CMD_KEY, CMD_LCDMEM = 0, 1, 2, 3
|
||||
# =============================================================================
|
||||
# _sock:与 DTU 装置的 TCP socket,None 表示未连接
|
||||
_sock: Optional[socket.socket] = None
|
||||
# _init_info:初始化信息(width/height/mem_size),由 CMD_INIT 获取
|
||||
_init_info: Optional[dict] = None
|
||||
# _screen_clients:当前需要接收屏幕推送的 WebSocket 客户端 sid 集合
|
||||
_screen_clients: Set[str] = set()
|
||||
# _refresh_thread:后台刷新线程,持续拉取屏幕并推送
|
||||
@@ -94,12 +92,15 @@ def parse_frame(raw: bytes) -> Optional[Tuple[int, bytes]]:
|
||||
帧格式: [TAG(1)][cmd(1)][len_hi(1)][len_lo(1)][data(length)][crc(1)]
|
||||
"""
|
||||
if len(raw) < 6 or raw[0] != TAG_DEVICE: # 至少 6 字节且帧头为 TAG_DEVICE
|
||||
print("[parse_frame] 错误: 帧太短或帧头不是 TAG_DEVICE(0xBB), len=%d" % len(raw))
|
||||
return None
|
||||
length = (raw[2] << 8) | raw[3] # 大端序解析数据区长度
|
||||
if len(raw) < 4 + length + 1: # 检查是否收齐整帧(头4字节+数据+CRC1字节)
|
||||
print("[parse_frame] 错误: 数据不完整, 需要 %d 字节, 实际 %d 字节" % (4 + length + 1, len(raw)))
|
||||
return None
|
||||
data = raw[4:4 + length] # 提取数据区
|
||||
if calc_crc(data) != raw[4 + length]: # CRC 校验失败
|
||||
print("[parse_frame] 错误: CRC 校验失败")
|
||||
return None
|
||||
return (raw[1], data) # 返回 (命令码, 数据)
|
||||
|
||||
@@ -113,7 +114,7 @@ def connect(host: str, port: int = PORT) -> bool:
|
||||
建立与 DTU 装置的 TCP 连接。
|
||||
若有旧连接则先关闭;连接时超时 3 秒;连接成功后设为 2 秒。
|
||||
"""
|
||||
global _sock, _init_info
|
||||
global _sock
|
||||
try:
|
||||
if _sock:
|
||||
_sock.close() # 关闭旧连接
|
||||
@@ -122,18 +123,21 @@ def connect(host: str, port: int = PORT) -> bool:
|
||||
_sock.connect((host, port)) # 连接目标主机和端口
|
||||
_sock.settimeout(2.0) # 连接成功后收发超时 2 秒
|
||||
return True
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
print("[connect] 错误: 连接失败 - %s" % e)
|
||||
return False
|
||||
|
||||
|
||||
def _send(cmd: int, data: bytes = b"") -> bool:
|
||||
"""发送一帧到设备"""
|
||||
if not _sock:
|
||||
print("[_send] 错误: 未连接设备")
|
||||
return False
|
||||
try:
|
||||
_sock.sendall(build_frame(cmd, data)) # 构造帧并一次性发送
|
||||
return True
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
print("[_send] 错误: 发送失败 - %s" % e)
|
||||
return False
|
||||
|
||||
|
||||
@@ -143,16 +147,20 @@ def _recv() -> Optional[Tuple[int, bytes]]:
|
||||
至少需 5 字节(4 字节头+1 字节数据或 CRC);根据头中 length 检查是否收齐整帧。
|
||||
"""
|
||||
if not _sock:
|
||||
print("[_recv] 错误: 未连接设备")
|
||||
return None
|
||||
try:
|
||||
data = _sock.recv(256 * 1024) # 单次接收最多 256KB
|
||||
if len(data) < 5: # 至少需要 5 字节(4 头 + 1 数据/CRC)
|
||||
print("[_recv] 错误: 接收数据太短, len=%d" % len(data))
|
||||
return None
|
||||
length = (data[2] << 8) | data[3] # 解析数据区长度
|
||||
if len(data) < 4 + length + 1: # 数据不完整
|
||||
print("[_recv] 错误: 数据不完整, 需要 %d 字节, 实际 %d 字节" % (4 + length + 1, len(data)))
|
||||
return None
|
||||
return parse_frame(data[:4 + length + 1]) # 解析并返回 (cmd, data)
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
print("[_recv] 错误: 接收异常 - %s" % e)
|
||||
return None
|
||||
|
||||
|
||||
@@ -167,8 +175,10 @@ def fetch_screen() -> Optional[bytes]:
|
||||
发送 CMD_LCDMEM + 起始地址 0;设备回复 payload 前 4 字节为地址,后续为位图,返回 payload[4:]。
|
||||
"""
|
||||
if not _sock:
|
||||
print("[fetch_screen] 错误: 未连接设备")
|
||||
return None
|
||||
if not _send(CMD_LCDMEM, struct.pack(">I", 0)): # 发送读取显存命令,起始地址 0(大端 4 字节)
|
||||
print("[fetch_screen] 错误: 发送 CMD_LCDMEM 失败")
|
||||
return None
|
||||
result = _recv() # 接收设备回复
|
||||
if result and result[0] == CMD_LCDMEM: # 确认为 LCDMEM 回复
|
||||
@@ -176,6 +186,7 @@ def fetch_screen() -> Optional[bytes]:
|
||||
if len(payload) >= 4: # 前 4 字节为地址,后面是位图
|
||||
return payload[4:]
|
||||
return payload or None
|
||||
print("[fetch_screen] 错误: 未收到有效 LCDMEM 回复")
|
||||
return None
|
||||
|
||||
|
||||
@@ -197,19 +208,19 @@ def mono_to_png(data: bytes, width: int, height: int) -> Optional[bytes]:
|
||||
img.save(buf, format="PNG") # 保存为 PNG 格式
|
||||
return buf.getvalue() # 返回 PNG 字节流
|
||||
except ImportError:
|
||||
print("[mono_to_png] 错误: 缺少 PIL/Pillow, 请执行 pip install pillow")
|
||||
return None
|
||||
|
||||
|
||||
def disconnect_device():
|
||||
"""关闭与设备的连接"""
|
||||
global _sock, _init_info
|
||||
global _sock
|
||||
try:
|
||||
if _sock:
|
||||
_sock.close() # 关闭 socket
|
||||
_sock = None # 清空引用
|
||||
_init_info = None # 清空初始化信息
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
print("[disconnect_device] 错误: 关闭连接时异常 - %s" % e)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
@@ -226,7 +237,7 @@ def _screen_refresh_loop():
|
||||
if _screen_clients and _sock: # 有客户端且已连接设备
|
||||
data = fetch_screen() # 拉取屏幕位图
|
||||
if data:
|
||||
info = _init_info or {} # 获取宽高,缺省 160x160
|
||||
info = {"width": 160, "height": 160} # 设置长宽 160x160
|
||||
w, h = info.get("width", 160), info.get("height", 160)
|
||||
png = mono_to_png(data, w, h) # 转为 PNG
|
||||
if png:
|
||||
|
||||
@@ -402,12 +402,15 @@
|
||||
// 创建临时 URL
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
// 图片加载完成后
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
// 设置 canvas 尺寸
|
||||
canvas.getContext('2d').drawImage(img, 0, 0);
|
||||
// 绘制到 canvas
|
||||
// 图片加载完成后,放大一倍显示(160x160 -> 320x320)
|
||||
const scale = 2;
|
||||
canvas.width = img.width * scale;
|
||||
canvas.height = img.height * scale;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
// 关闭平滑,像素清晰放大
|
||||
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
|
||||
// 绘制到 canvas(2 倍尺寸)
|
||||
canvas.style.display = 'block';
|
||||
placeholder.style.display = 'none';
|
||||
// 显示 canvas,隐藏占位符
|
||||
@@ -467,7 +470,7 @@
|
||||
});
|
||||
document.querySelector('.menu-item.exit').onclick = doDisconnect;
|
||||
// 断开按钮 -> 执行断开
|
||||
document.getElementById('btnAbout').onclick = () => alert('远程显示工具\n与 RemoDispBus 协议兼容\n端口 7003');
|
||||
document.getElementById('btnAbout').onclick = () => alert('阜阳师范大学物理与电子工程学院\nDTU 远程液晶屏幕通信工具');
|
||||
// 关于按钮 -> 弹出说明
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user