feat: 链路控制、延迟校准与长测工具,补全文档
- 固件:新增 link_control / stream_control,覆盖运行中 Wi-Fi 断线恢复、取帧节拍、 温控与质量/帧率减载;UDP 发送增加有界重试预算与帧期限,PSRAM JPEG 直发减少拷贝。 - 协议:重组器严格校验分片布局,统计未收齐、超时与完全缺失的帧,处理帧号回绕与设备重启。 - 桌面端:视频改 latest-value 通道并前置帧时间标记,拒绝积压和慢解码的过期画面;新增 延迟标记页与 --latency-report 校准,完善录制、服务端与退出流程。 - 文档与脚本:新增硬件、开发、延迟、功耗、实时性、稳定性文档和改动记录,重写根 README; 新增构建、性能、延迟与串口长测脚本,以及长测客户端脚本。 - 构建:固定 esp-1.97.0.0 工具链,分区表随构建复制,更新 sdkconfig 与忽略规则。
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
|
||||
mod commands;
|
||||
mod demo;
|
||||
mod latency;
|
||||
mod recording;
|
||||
mod server;
|
||||
mod state;
|
||||
@@ -42,6 +43,7 @@ const USAGE: &str = "\
|
||||
|
||||
--role <team|referee> 身份。默认看配置文件;没有配置文件时是 referee
|
||||
--config <路径> 配置文件位置
|
||||
--latency-report <路径> 打开裁判端屏幕标记校准,写入新的本地 NDJSON 报告
|
||||
--demo 演示模式:画面与血量都是本地合成的
|
||||
--list 打印发现的摄像头与装甲板后退出
|
||||
-h, --help 显示这段帮助
|
||||
@@ -78,6 +80,7 @@ fn main() {
|
||||
struct Args {
|
||||
role: Option<Role>,
|
||||
config: Option<PathBuf>,
|
||||
latency_report: Option<PathBuf>,
|
||||
demo: bool,
|
||||
list: bool,
|
||||
help: bool,
|
||||
@@ -104,6 +107,9 @@ impl Args {
|
||||
"--config" => {
|
||||
args.config = it.next().map(PathBuf::from);
|
||||
}
|
||||
"--latency-report" => {
|
||||
args.latency_report = it.next().map(PathBuf::from);
|
||||
}
|
||||
other => {
|
||||
// 见模块文档:macOS 的 .app 启动参数与 shell 里的笔误都可能出现在这里,
|
||||
// 但报错的代价(窗口起不来)远大于收益。
|
||||
@@ -124,7 +130,10 @@ fn run() -> Result<(), Box<dyn Error>> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let config_path = args.config.clone().unwrap_or_else(config::default_config_path);
|
||||
let config_path = args
|
||||
.config
|
||||
.clone()
|
||||
.unwrap_or_else(config::default_config_path);
|
||||
|
||||
// 首次启动时导入旧客户端的配置,并把旧文件改名成 .bak。
|
||||
let (mut config, notes) = config::load_with_migration(&config_path)?;
|
||||
@@ -134,6 +143,10 @@ fn run() -> Result<(), Box<dyn Error>> {
|
||||
if let Some(role) = args.role {
|
||||
config.role = role;
|
||||
}
|
||||
if args.latency_report.is_some() && config.role != Role::Referee {
|
||||
return Err("Latency calibration requires a referee test configuration".into());
|
||||
}
|
||||
let latency_recorder = latency::Recorder::new(args.latency_report.clone())?;
|
||||
|
||||
for note in ¬es {
|
||||
log::info!("{note}");
|
||||
@@ -150,8 +163,7 @@ fn run() -> Result<(), Box<dyn Error>> {
|
||||
config_path.display()
|
||||
);
|
||||
|
||||
let (state, video_socket, armor_socket) =
|
||||
AppState::new(config_path, config, notes, args.demo)?;
|
||||
let (state, video_socket, armor_socket) = AppState::new(config_path, config, notes, args.demo)?;
|
||||
|
||||
// 视频端口绑不上时没有 socket,接收线程也就没有意义——界面会显示那条说明。
|
||||
if let Some(socket) = video_socket {
|
||||
@@ -219,7 +231,10 @@ fn run() -> Result<(), Box<dyn Error>> {
|
||||
let app = tauri::Builder::default()
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.manage(Arc::clone(&state))
|
||||
.manage(latency_recorder)
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
latency::latency_enabled,
|
||||
latency::latency_sample,
|
||||
commands::stream_info,
|
||||
commands::get_snapshot,
|
||||
commands::get_config,
|
||||
|
||||
Reference in New Issue
Block a user