Files
DTU-RemtoeLCD/README.md
T

7.6 KiB
Raw Blame History

DTU-RemoteLCD - 远程显示通信工具

与 RemoDispBus 协议兼容的远程 LCD 显示与按键模拟工具。通过网络连接 DTU 装置,在 Web 浏览器中实时查看 LCD 画面并模拟按键操作,适用于调试、监控等场景。

功能特性

  • 实时屏幕显示:将装置 LCD 显存以 1bpp 位图形式拉取并渲染为 PNG
  • 按键模拟:支持方向键、确认、返回、复归等按键
  • WebSocket 传输:采用 Socket.IO,服务端主动推送,约 100ms 刷新
  • 跨平台:浏览器访问,无需安装客户端

环境要求

  • Python 3.7+
  • 与 DTU 装置网络互通(默认端口 7003)

快速开始

1. 创建虚拟环境

在项目根目录下创建名为 .venv 的虚拟环境(需 Python 3.7+,已在 Python 3.14.7 验证):

# Windows (PowerShell)
python -m venv .venv
# Linux / macOS
python3 -m venv .venv

2. 激活虚拟环境

# Windows (PowerShell)
.\.venv\Scripts\Activate.ps1
# Windows (CMD)
.venv\Scripts\activate.bat
# Linux / macOS
source .venv/bin/activate

激活后命令行前缀会出现 (.venv);后续步骤也可直接使用 .venv 内的解释器而无需激活(见下方替代写法)。

3. 安装依赖

pip install -r requirements.txt

已验证的依赖版本:

依赖 版本
Flask 3.1.3
Flask-SocketIO 5.6.1
python-socketio 5.17.0
Pillow 12.3.0
loguru 0.7.3

4. 启动服务

python remo_disp_server.py [装置IP]

未激活虚拟环境时,可直接指定 venv 内解释器:

# Windows (PowerShell)
.\.venv\Scripts\python.exe remo_disp_server.py
.\.venv\Scripts\python.exe remo_disp_server.py 192.168.253.3   # 预连接装置
# Linux / macOS
.venv/bin/python remo_disp_server.py [装置IP]

启动后访问 http://localhost:8181。

5. 退出虚拟环境

deactivate

使用说明

  • 点击「连接」→ 输入装置 IP 和端口(默认 7003)→ 连接
  • 左侧显示装置 LCD 画面(约 100ms 刷新)
  • 右侧使用方向键、确认、复归、返回进行按键操作
  • 点击「断开」断开与装置的连接

打包为 exe(Windows)

在项目目录下执行(建议先激活虚拟环境,或使用 .venv 内解释器):

# 安装 PyInstaller 后打包
pip install pyinstaller
python -m PyInstaller remo_disp_server.spec --noconfirm

或直接双击运行 build_exe.bat(其内部使用当前激活环境的 python,因此请先激活 .venv 再运行)。

打包完成后可执行文件为 dist\remo_disp_server.exe。双击运行,或在命令行:

dist\remo_disp_server.exe
dist\remo_disp_server.exe 192.168.253.3

运行后浏览器访问 http://localhost:8181。日志会输出到控制台,同目录下会生成 remo_disp.log。

项目结构

DTU-RemoteLCD/
├── remo_disp_server.py    # Web 服务(Flask + Socket.IO)
├── remo_disp_server.spec  # PyInstaller 打包配置
├── build_exe.bat           # 一键打包脚本(Windows)
├── remo_disp_ui.html      # Web 前端页面
├── requirements.txt       # Python 依赖
├── .venv/                 # Python 虚拟环境(本地创建,不入库)
├── static/                # 静态资源(可选)
│   └── favicon.ico        # 网站图标
└── README.md

协议说明

项目 说明
端口 7003
工具 → 装置 [0xAA][功能码][长度高][长度低][数据...][CRC]
装置 → 工具 [0xBB][功能码][长度高][长度低][数据...][CRC]
CRC 数据区逐字节异或,取低 8 位
刷新屏幕请求
AA 03 00 04 00 00 00 00 00   

客户端解析(remo_disp_server.py):与 MCU 端(ui_net_sink.c 的 rm_parser_feed) 同款逐字节状态机解析:TAG(0xBB) 定界 → CMD → LEN(16 位大端) → DATA → CRC(数据区异或); 一帧可跨多个 TCP 包;长度字段设上限(RM_MAX_RX_PAYLOAD)防损坏长度锁死状态机; 失步后在下一个帧头自动重同步。两端解析策略一致,便于联调对拍。

功能码:

码 名称 说明
0 KEEPLIVE 保活
1 INIT 初始化,获取屏幕宽高、显存大小
2 KEY 按键
3 LCDMEM 读取显存(屏幕画面)

延迟确认抑制(性能关键,2026-09-22 实测引入)

现象:拉取一帧 LCDMEM(3209B)原本中位 68.8ms,其中约 52ms 卡在帧尾那 137B 小段上。

根因(已在 DTU 侧台架确证,见 STM32F4-Base 仓库 docs/测试说明/链路延迟测试说明.md §7.3): DTU 侧 CH395F 的 MSS=1024、发送 FIFO=1024B,因此每次 1024B 写恰好是满 MSS 段(立即发送); 而 3209B = 3×1024 + 137B,最后这段是次 MSS 段 → 芯片按 Nagle 规则扣住它,等前一数据被 ACK。 Windows 默认延迟确认把该 ACK 推迟 40~200ms,整帧因此被拖住。

本工具的处理(remo_disp_server.py,两条路径自动择一):

路径 条件 做法 实测帧耗时
A. 关闭延迟确认 Windows(默认) WSAIoctl(SIO_TCP_SET_ACK_FREQUENCY=1)(ctypes 直调;Python socket.ioctl 白名单不接受该码) 20.7ms
B. 入站"轻推"兜底 非 Windows / A 失败 收帧途中若帧已开始却停顿 ≥5ms,向装置补发 1 个 0x00(装置只认帧头 0xBB,会丢弃)→ 该段捎带 ACK 29.4ms

连接时会打印 [connect] 延迟确认抑制: 已关闭(ACK frequency=1) 或 未生效(改用入站轻推兜底)。 两条路径均不需要改协议、不需要改装置固件;日志级别调至 DEBUG 可看到 [_recv] 轻推 1 字节捎带 ACK。

按键映射

键名 协议码 说明
U 0x02 上
D 0x40 下
L 0x10 左
R 0x08 右
ENT 0x20 确认
ESC 0x01 返回/取消
RESET 0x04 复归
F2 0x80 F2

依赖说明

依赖 用途
Flask Web 框架
flask-socketio WebSocket 支持
python-socketio Socket.IO 服务端
Pillow 1bpp 位图转 PNG
loguru 结构化日志、错误追踪

日志与调试

  • 后端使用 loguru 输出日志,默认会打印到控制台,并写入当前目录下的 remo_disp.log。
  • 在 remo_disp_server.py 顶部有 LOG_LEVEL 常量:
    • LOG_LEVEL = "INFO":只输出 INFO/WARNING/ERROR 级别日志(默认)。
    • LOG_LEVEL = "DEBUG":输出包括 DEBUG 在内的详细调试信息。
  • exe 版本(remo_disp_server.exe)同样会在运行目录生成 remo_disp.log,方便线下排查问题。

配置说明

  • Web 服务端口:默认 8181,在 remo_disp_server.py 的 main() 中修改
  • 装置端口:默认 7003,连接时可输入自定义端口
  • Favicon:将 favicon.ico 放入 static/ 目录即可显示网站图标
  • 接收耐心参数(remo_disp_server.py 顶部,装置响应慢时可调节):
    • RECV_CHUNK_TIMEOUT = 3.0 — 单次 recv 最长等待秒数,超时仅表示"暂无数据",不算失败
    • RECV_FIRST_BYTE_TIMEOUT = 3.0 — 发出请求后等待响应首字节的秒数,全程无字节判为对端无应答,快速失败
    • RECV_TOTAL_BUDGET = 10.0 — 收齐一整帧的总时间预算(秒)。MCU 经 CH395F 按 1KB 块握手发送,整帧(如 3209 字节的 LCDMEM)可能耗时 0.5~3 秒以上;若装置更慢可适当调大

许可证

本项目仅供内部调试使用。