小鸿 SE AI 门锁链路拆解:使用 FRB构建最终形态
项目源码:小鸿 SE AI 门锁平台 AtomGit 仓库
FRB 项目:oh-flutter/flutter_rust_bridge
Rust 社区:开放原子旋武开源社区
从摄像头上的一个人脸框,到 HarmonyOS PC 上持续更新的实时画面,中间需要经过 ESP32-P4 推理、板内 UART、WS63 缓存、星闪 SSAP 和 Flutter 展示。小鸿 SE AI 门锁平台已经将这条链路接通,本文进一步讨论如何通过 FRB 为它增加可独立测试的 Rust 协议解析层。
先说明项目现状:当前正式仓库使用 Flutter + Dart Gateway + ArkTS + WS63 + ESP32-P4,README 明确记录已裁剪 Rust/FRB。本文的 FRB 部分是新增扩展方案;文中的设备实拍来自现有系统,不能作为 FRB 扩展已完成真机集成的证据。
本文会先介绍社区与框架,引用已有环境教程,再拆解现有数据闭环、给出 Rust STATUS 解析器和 Dart 接入方式,最后说明运行验证、Issue 反馈与 PR 贡献流程。
一、认识旋武社区与 FRB
1. 旋武社区:Rust 学习与开源协作入口
开放原子旋武开源社区是开放原子开源基金会旗下的 Rust 专项社区,围绕 Rust 学习、工具使用和开源项目协作建设生态。官网提供 Rust 发行版及镜像、学习资料、在线编码体验、社区项目和技术活动等资源。
对于希望将 Rust 引入 Flutter 或鸿蒙项目的开发者,可以先从社区资源了解语言和工程实践,再进入具体仓库阅读代码、反馈问题和贡献修复。社区提供学习交流入口,Issue 与 Pull Request 则让项目中的问题和解决过程可以持续追踪。
2. FRB:让 Dart 调用 Rust 的业务接口
flutter_rust_bridge(简称 FRB)是 Flutter/Dart 与 Rust 之间的跨语言绑定工具。开发者定义 Rust 函数和数据结构,通过代码生成器生成桥接代码,再从 Dart 调用这些接口、接收结果并处理错误。
本文使用的项目入口为:https://atomgit.com/oh-flutter/flutter_rust_bridge。鸿蒙接入说明、框架版本和相关问题,可从该仓库查阅与反馈。
在本次扩展中,FRB 只连接 Dart Gateway 与 Rust STATUS 解析器。NearLink 权限、扫描、配对和 SSAP 传输仍由 ArkTS 处理,ESP-DL 人脸检测仍运行在 P4 上。Rust 解析器不执行 AI 推理,也不提供开锁授权。
二、为什么为当前项目选择 FRB 扩展
现有 Dart 链路已经可用,引入 Rust 应解决具体的维护问题。STATUS 包字段少、边界清晰,适合用作第一次跨语言接入:先验证字节传递、类型映射、错误返回和原生库加载,再决定是否扩大迁移范围。
| 当前需求 | 扩展方式 | 预期收益 |
|---|---|---|
| 多处字节偏移容易写错 | Rust 集中解析 XH v1 STATUS | 通过固定字节样本检查长度、字节序和字段映射 |
| 协议错误不容易在 UI 测试中复现 | 解析器接受字节数组,返回结构或错误 | 无需连接开发板就能测试截断包和错误人数 |
| Flutter 页面需要稳定业务数据 | FRB 返回 DetectionStatus 与人脸框 | 页面使用结构化结果,减少手写跨语言转换 |
| 迁移需要可回退 | 先对比 Dart 与 Rust 两份结果 | 在不改变无线和 JPEG 链路的情况下定位差异 |
STATUS 包很小,跨桥调用开销可能高于解析计算本身,因此这里不承诺性能提升。引入 FRB 的主要价值是把协议校验集中到可测试的模块中;代价是增加 Rust 工具链、生成器版本管理,以及鸿蒙原生库构建与打包工作。
本次选型也有明确范围:先迁移 STATUS,JPEG 重组仍使用现有 Dart 实现。后续若要迁移图像链路,需要单独评估内存、分片处理和断线恢复,不能因为状态包已解析成功,就认为全部协议已经完成迁移。
三、环境搭建:引用教程并区分现有工程与扩展依赖
1. 基础环境参考两篇已有文章
- 《2026 年如何上车 Flutter-OH:环境搭建与上手流程》:用于准备 Flutter-OH、DevEco Studio、HarmonyOS SDK,了解工具链检查、真机运行与签名流程。
- 《Rust | VS Code搭建Rust开发环境的超详细图文教程总结(含Rust开发常用插件)》:用于了解 Rust、Cargo、VS Code 和常用扩展。该文主要以 Windows 为例,macOS 开发者应按本机平台准备编译与调试工具。
两篇教程分别解决 Flutter-OH 和 Rust 的基础环境问题。复现门锁项目时,还需使用包含 NearLinkKit 的 SDK,并按仓库说明准备 P4 与 WS63 固件。教程中的版本示例不能直接替代项目要求。
2. 当前仓库记录的环境
| 项目 | 仓库记录 |
|---|---|
| HarmonyOS PC | HAD-W24 |
| 系统版本 | 6.1.0.117 / OpenHarmony 6.1 |
| HarmonyOS SDK | 6.0.2(22),包含 NearLinkKit |
| Flutter | 支持 OHOS 的 Flutter 3.35 系列 |
| Dart | 应用 SDK 约束为 ^3.9.2 |
| WS63 | 小鸿 SE WS63,OpenHarmony mini 产品树,SDK v106 |
| ESP32-P4 | 小鸿 SE P4,ESP-IDF 5.4/5.5 工具链 |
获取现有工程:
git clone https://atomgit.com/xiaohong-ai/xiaohong-se-ai-lock-platform.git
cd xiaohong-se-ai-lock-platform/apps/xiaohong_se_manager
flutter pub get
flutter doctor -v
dart analyze lib test integration_test
当前 App 只保留 HarmonyOS 工程,不提供 macOS 桌面演示壳。完整运行还需要两颗芯片的匹配固件;首次只验证星闪连接时,可以先观察“等待 P4 相机帧”,但这不算图像链路验收通过。
3. FRB 扩展需要另外准备什么
本文扩展示例选用 FRB 2.13.0-beta.6。这是教程选择的版本,不是现有项目已经使用或验证过的依赖。Dart 包、Rust crate 和代码生成器应保持一致:
rustc --version
cargo --version
cargo install flutter_rust_bridge_codegen --version 2.13.0-beta.6
flutter_rust_bridge_codegen --version
新增目录和文件的目标结构如下:
apps/xiaohong_se_manager/
├── flutter_rust_bridge.yaml 新增:绑定生成配置
├── rust/
│ ├── Cargo.toml 新增:原生 crate
│ └── src/
│ ├── lib.rs 新增:模块入口
│ ├── protocol.rs 新增:纯 Rust 解析器
│ ├── api.rs 新增:FRB 包装
│ └── frb_generated.rs 生成器输出
├── lib/src/rust/ 生成器输出
└── rust_builder/ 需另行接入的原生构建插件
flutter_rust_bridge_codegen generate 负责生成绑定,并不会自动完成本工程的 OHOS 构建插件、交叉编译、HAR/HAP 打包和签名。第五节会分别说明主机解析验证和真机集成门槛。
四、项目开发细节:现有链路与 Rust 解析扩展
1. 当前系统的完整数据闭环
状态路径由 App 发起:Dart 每 350ms 查询一次状态,ArkTS 通过 SSAP 写入请求,WS63 与 P4 交换状态并更新缓存,随后把 STATUS 回传给 App。P4 是画面和人脸检测结果的数据源,WS63 不执行人脸检测。
画面路径使用 GET_FRAME 请求较新的 JPEG。P4 将图像分片交给 WS63,WS63 组装完成后更新缓存,再通过 FRAME_BEGIN、FRAME_CHUNK 和 FRAME_END 发给 App。Dart 完成校验后,Flutter 才显示图像。
可从以下文件阅读现有实现:
apps/xiaohong_se_manager/lib/services/device_gateway.dart
XH 包编码、状态轮询、STATUS 解析和 JPEG 重组
apps/xiaohong_se_manager/lib/models/device_models.dart
检测结果、人脸框、相机帧类型
apps/xiaohong_se_manager/lib/features/dashboard/
实时监控与当前会话访客记录
apps/xiaohong_se_manager/ohos/entry/src/main/ets/entryability/EntryAbility.ets
NearLink 权限、配对、服务发现与通知
firmware/ws63/src/sle_server/sle_server_task.c
SSAP 请求与响应
firmware/ws63/src/uart_bridge/
P4 状态缓存与图像组装
firmware/esp32-p4/
摄像头、LCD 与 ESP-DL
2. XH v1 包头与 STATUS 字段
App 与 WS63 的包使用小端整数,包头为 10 字节:
| 偏移 | 长度 | 含义 |
|---|---|---|
| 0 | 2 | Magic:0x58 0x48,即 XH |
| 2 | 1 | 包头版本,当前为 1 |
| 3 | 1 | 消息类型 |
| 4 | 4 | request_sequence |
| 8 | 2 | payload_length |
| 10 | N | payload |
STATUS 类型为 0x81。下面的偏移均从 payload 开头计算:
| 偏移 | 类型 | 字段 |
|---|---|---|
| 0 | u16 | protocol_version |
| 2 | u32 | last_request_sequence |
| 6 | u32 | inference_sequence |
| 10 | u32 | timestamp_ms |
| 14 | u16 | latency_ms |
| 16 / 18 | u16 / u16 | 图像宽度 / 高度 |
| 20 | u8 | flags:bit0 上报启用、bit1 检测器就绪、bit2 结果有效 |
| 21 | u8 | 人脸数,最多 4 |
| 22 起 | 每张 10 字节 | 置信度千分值、x1、y1、x2、y2,均为 u16 |
因此合法 STATUS 的 payload 长度必须为 22 + face_count * 10。包头请求序号、负载中的最近请求序号和推理序号是三个不同字段,不能因为它们都叫 sequence 就合并使用。
3. 先提取不依赖 Flutter 的纯 Rust 解析器
将下面代码放入新增的 rust/src/protocol.rs。它保留现有 Dart 对包头、负载长度和人脸记录的主要检查,同时完整返回协议版本和最近请求序号,便于后续比对。
#[derive(Clone, Debug, PartialEq)]
pub struct FaceBox {
pub score: f64,
pub x1: u16,
pub y1: u16,
pub x2: u16,
pub y2: u16,
}
#[derive(Clone, Debug, PartialEq)]
pub struct DetectionStatus {
pub request_sequence: u32,
pub protocol_version: u16,
pub last_request_sequence: u32,
pub inference_sequence: u32,
pub timestamp_ms: u32,
pub latency_ms: u16,
pub image_width: u16,
pub image_height: u16,
pub flags: u8,
pub faces: Vec<FaceBox>,
}
pub fn parse_status(packet: &[u8]) -> Result<DetectionStatus, String> {
if packet.len() < 10 {
return Err("XH_PACKET_TOO_SHORT".into());
}
if packet[..2] != [0x58, 0x48] || packet[2] != 1 {
return Err("XH_BAD_MAGIC_OR_VERSION".into());
}
if packet[3] != 0x81 {
return Err("XH_NOT_STATUS".into());
}
let payload_len = u16::from_le_bytes([packet[8], packet[9]]) as usize;
if payload_len != packet.len() - 10 {
return Err("XH_LENGTH_MISMATCH".into());
}
let p = &packet[10..];
if p.len() < 22 {
return Err("XH_STATUS_TOO_SHORT".into());
}
let count = usize::from(p[21]);
if count > 4 || p.len() != 22 + count * 10 {
return Err("XH_FACE_RECORD_MISMATCH".into());
}
let u16le = |i| u16::from_le_bytes([p[i], p[i + 1]]);
let u32le = |i| u32::from_le_bytes([p[i], p[i + 1], p[i + 2], p[i + 3]]);
let faces = (0..count)
.map(|index| {
let i = 22 + index * 10;
FaceBox {
score: f64::from(u16le(i)) / 1000.0,
x1: u16le(i + 2),
y1: u16le(i + 4),
x2: u16le(i + 6),
y2: u16le(i + 8),
}
})
.collect();
Ok(DetectionStatus {
request_sequence: u32::from_le_bytes([packet[4], packet[5], packet[6], packet[7]]),
protocol_version: u16le(0),
last_request_sequence: u32le(2),
inference_sequence: u32le(6),
timestamp_ms: u32le(10),
latency_ms: u16le(14),
image_width: u16le(16),
image_height: u16le(18),
flags: p[20],
faces,
})
}
解析器先检查固定长度,再读取字段;确认人脸数和记录长度后才遍历数组,避免对截断包越界读取。错误返回明确原因,而不是将错误包解释为“没有人脸”。
这里读取并返回 payload 中的 protocol_version,没有新增严格版本拒绝策略;现有 Dart STATUS 解析也未执行这项检查。保留两边行为有助于第一次迁移比对。后续若按协议增加负载版本、坐标范围或置信度范围校验,应独立说明规则变化并补充测试。
解析成功也不等于所有业务条件成立。请求序号是否属于当前会话、数据是否过期,应由请求与会话管理层判断,不能靠这个无状态函数推断。
4. 添加 FRB 包装与生成配置
新增 rust/Cargo.toml:
[package]
name = "xiaohong_se_protocol"
version = "0.1.0"
edition = "2024"
[lib]
crate-type = ["cdylib", "staticlib"]
[dependencies]
flutter_rust_bridge = "=2.13.0-beta.6"
在 rust/src/api.rs 中包装解析器,并把初始化函数放在生成器扫描的 API 模块中:
pub use crate::protocol::{DetectionStatus, FaceBox};
#[flutter_rust_bridge::frb(init)]
pub fn init_app() {
flutter_rust_bridge::setup_default_user_utils();
}
#[flutter_rust_bridge::frb(sync)]
pub fn parse_status_packet(packet: Vec<u8>) -> Result<DetectionStatus, String> {
crate::protocol::parse_status(&packet)
}
rust/src/lib.rs 导出模块:
pub mod api;
pub mod protocol;
mod frb_generated;
应用根目录中的 flutter_rust_bridge.yaml:
rust_input: crate::api
rust_root: rust/
dart_output: lib/src/rust
在现有 pubspec.yaml 的 dependencies 中加入 flutter_rust_bridge: 2.13.0-beta.6。原生插件接入完成后,还需加入对应的本地插件依赖;不能先写一个不存在的 rust_builder 路径并认为集成已经完成。
frb(sync) 明确让 Dart 同步取得解析结果,与下一节的同步 _handlePacket 分派保持一致。若使用默认异步接口,则 Dart 必须 await,并另外处理迟到结果、断线和新旧会话顺序;不能把返回的 Future 当作状态对象直接读取。
5. Dart 只替换 STATUS 分支
生成绑定并完成原生库接入后,在 Gateway 中引入接口:
import 'package:flutter/foundation.dart';
import 'package:xiaohong_se_manager/src/rust/api.dart' as rust;
保留 _handlePacket 的包头与总长度检查,把原 STATUS 分支调用替换为 _handleStatusWithRust(packet)。这里传入完整包,因为 Rust 解析器还要读取包头:
void _handleStatusWithRust(Uint8List packet) {
try {
final status = rust.parseStatusPacket(packet: packet);
_results.add(
FaceDetectionResult(
deviceId: _nearLinkDeviceId,
timestampMs: BigInt.from(status.timestampMs),
sequence: status.inferenceSequence,
faceCount: status.faces.length,
latencyMs: status.latencyMs,
imageWidth: status.imageWidth,
imageHeight: status.imageHeight,
faces: status.faces.map((face) => FaceBox(
score: face.score,
x1: face.x1,
y1: face.y1,
x2: face.x2,
y2: face.y2,
)).toList(),
modelVersion: (status.flags & 0x06) == 0x06
? 'ESPDet-Pico 416'
: 'ESPDet-Pico 416(等待 P4 相机帧)',
),
);
} catch (error) {
debugPrint('STATUS 协议解析失败:$error');
}
}
这段是放入现有 Gateway 类的接入示例,沿用其 Uint8List、FaceDetectionResult、FaceBox 和结果流。解析失败时不发布新的有效结果;页面对旧结果的保留时间和过期提示仍需另行设计。
正式切换前建议先进行双解析比对:同一包同时交给 Dart 和 Rust,按字段比较人数、坐标、宽高、flags、推理序号及时间戳。现有 Dart 未暴露的版本和最近请求序号,应通过协议样本核对。新解析器失败或结果不一致时记录差异,影子阶段继续使用原 Dart 结果。
初始化策略也要区分阶段:影子验证时可以捕获 FRB 初始化失败、禁用扩展并继续原链路;正式以 Rust 为主路径后,初始化失败应明确展示错误,不能把没有运行解析器的页面当作集成成功。
6. 扩展后的链路和保留的 JPEG 检查
图像链路各处的限制不同:P4 UART 分片最大 1024 字节,WS63 完整 JPEG 缓存上限 40 KiB,SSAP JPEG 数据块最大 220 字节,App 完整帧缓冲上限 64 KiB。整条链路的完整 JPEG 上限受 WS63 限制,为 40 KiB。
现有 Dart 校验请求序号、图像序号、offset 连续性、分片长度、总长度与 JPEG FFD8/FFD9 首尾标记。当前 XH v1 SSAP 图像协议没有定义图像 CRC 字段,现有 Dart 重组代码也未计算整图 CRC,不能把其他项目的 CRC 校验能力写成本项目已实现功能。
五、运行方式、效果图与验证结果
1. 先运行现有 HarmonyOS 应用
在 apps/xiaohong_se_manager/ 中执行:
flutter pub get
flutter devices
flutter run -d <HARMONY_DEVICE_ID>
将设备标识替换为实际 HarmonyOS PC。构建签名包可使用 DevEco Studio 打开该应用的 ohos/,在 Project Structure 中配置本机签名,再执行 Build Hap。仓库记录的典型输出位置为:
apps/xiaohong_se_manager/ohos/entry/build/default/outputs/default/
entry-default-signed.hap
回到仓库根目录,安装并启动:
hdc list targets
hdc -t <HARMONY_DEVICE_ID> install -r \
apps/xiaohong_se_manager/ohos/entry/build/default/outputs/default/entry-default-signed.hap
hdc -t <HARMONY_DEVICE_ID> shell aa start \
-a EntryAbility \
-b com.xiaohongse.xiaohong_se_manager
运行前确认 P4 与 WS63 都已烧录匹配固件并启动。App 首次连接需允许星闪权限,扫描目标广播 xiaohong_se_lock,确认配对后发现服务 0x2222、属性 0x2323 并订阅通知。点击开始检测,观察 JPEG 帧序号、人脸数和推理耗时是否持续更新。
两颗芯片的构建与烧录按项目 README、firmware/esp32-p4/README.md 和 firmware/ws63/README.md 执行。TTL Type-C 用于烧录和日志,App 的运行数据通过无线星闪传输。
2. 原有真机效果图


两张照片沿用原有现场资料,展示相机、LCD 和人脸检测框的实际运行。它们证明的是现有系统中的视觉功能,不证明人物身份、开锁授权或真实锁舌动作,也不证明新增 FRB 库已经装载。
当前项目只做人脸检测,访客记录最多保留当前 App 会话的 50 条,重启后不恢复。这一能力不能等同于身份识别或长期访客审计。
3. 本文解析器已执行的主机测试
本文配套提供 protocol.rs 和 protocol_tests.rs。解析器不依赖 FRB,可直接用 Rust 工具链测试:
rustc --edition 2024 --test protocol_tests.rs -o protocol-tests
./protocol-tests
本次使用 rustc 1.93.0 实际执行,结果为 10 passed,0 failed。测试使用人工构造的协议数据,不使用真实访客图像,覆盖:
| 测试 | 检查点 |
|---|---|
| 完整单人脸包 | 所有状态字段、小端序、置信度 0.923 与坐标 |
| 零人脸和四人脸 | 合法数量边界 |
| 逐字节截断 | 合法包每个截断位置都返回错误 |
| 错误 Magic 与包头版本 | 拒绝不匹配包头 |
| 非 STATUS 类型 | 不把图像分片当状态包 |
| 包头声明长度错误 | 拒绝长度不一致 |
| 固定负载不足 | 包头长度匹配时仍拒绝不足 22 字节的状态 |
| 五张人脸 | 拒绝超过当前协议限制 |
| 人脸记录缺字节或多字节 | 记录长度必须精确匹配 |
| payload 版本字段 | 完整返回字段,未偷偷引入新的拒绝策略 |
这组测试验证纯 Rust 解析逻辑,没有执行 FRB codegen、Flutter 绑定调用或鸿蒙 HAP 装载验证。
4. FRB 扩展真正接入 HAP 的步骤
完成第四节新增文件后,按以下顺序继续集成:
- 配置 Dart FRB 依赖,在应用目录执行
flutter pub get和flutter_rust_bridge_codegen generate,确认两端生成文件更新。 - 按指定 FRB 仓库的鸿蒙接入说明配置原生构建插件及 OHOS target,构建
xiaohong_se_protocol并将目标架构动态库打包到 HAP。 - 加入实际存在的本地插件依赖,在
main.dart中、runApp前初始化RustLib。库名和加载方式要与插件构建产物一致。 - 启动目标 HAP,实际调用一条合法 STATUS 和一条错误包,确认结构映射和错误传播。
- 用同一批真实 STATUS 样本进行 Dart/Rust 比对,覆盖重连、重复包、截断包和异常字段。
- 结果一致后切换 STATUS 主路径,重新检查实时状态、JPEG 接收及断开清理。
应用初始化形态可参考:
import 'package:flutter/material.dart';
import 'package:xiaohong_se_manager/app.dart';
import 'package:xiaohong_se_manager/src/rust/frb_generated.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await RustLib.init();
runApp(const XiaohongSeApp());
}
这段假设生成配置和构建插件已经提供正确的库加载配置;若使用显式加载,应按最终动态库名配置 externalLibrary。不能仅凭这几行入口代码宣称 OHOS 原生集成完成。
绑定生成成功后,在对应位置执行检查:
# 在 apps/xiaohong_se_manager 中执行。
cargo test --manifest-path rust/Cargo.toml
dart analyze lib test integration_test
# 连接并准备好真机后执行硬件集成测试。
flutter test integration_test/simple_test.dart -d <HARMONY_DEVICE_ID>
这些 FRB 命令只适用于新增文件和依赖后的扩展工作区;原仓库没有 rust/Cargo.toml 和生成配置,不能直接执行。
5. 验收状态按实际证据区分
| 检查项 | 当前依据 | 状态或限制 |
|---|---|---|
| P4 相机、LCD、人脸检测 | 原有现场实拍 | 已有演示资料 |
| P4 → WS63 → HarmonyOS 状态与 JPEG | 仓库现有运行记录 | 正式链路仍由 Dart Gateway 解析 |
| 本文 Rust STATUS 解析器 | 10 项主机单测 | 本次测试通过 |
| FRB 绑定与 Dart 结构映射 | 本文接入方案 | 待实际生成并验证 |
| FRB 扩展真机 HAP | 需完成插件、原生构建和安装 | 待集成验证 |
| 人脸身份识别与活体检测 | 当前仅检测框 | 不属于现有完成能力 |
| 真实锁舌执行与量产安全能力 | 当前原型范围 | 尚不能据此宣称完成 |
六、FAQ:问题反馈、修复和 PR
1. 遇到框架问题,如何提 Issue?
先判断故障是否来自 FRB。现有正式仓库没有 FRB,当前星闪连接、P4 画面和 Dart JPEG 问题应优先到门锁项目仓库的 Issues 反馈。扩展后若最小示例仍能复现绑定生成、类型映射或原生调用异常,则进入 FRB 项目仓库的 Issues。
提交前搜索相同报错和版本,按模板填写;最少应包含:
标题:[OHOS][版本] 操作与实际错误
环境:
- 主机系统、CPU 架构:
- Flutter-OH / Dart / Rust / Cargo:
- FRB Dart、Rust 依赖和 codegen 版本(仅扩展路径):
- DevEco / SDK / 目标 HarmonyOS 设备:
- 项目 commit、P4 与 WS63 固件版本:
复现步骤:
预期结果:
实际结果:
完整错误日志或堆栈:
最小复现仓库、补丁或人工构造的协议样本:
已尝试的排查步骤及结果:
FRB 问题尽量缩小为一个 Rust 函数和一次 Dart 调用。协议问题给出消息类型、长度、相关序号和字段差异;先使用人工构造包复现,避免提交真实人脸 JPEG、设备地址、证书或口令。
2. 问题解决后,如何提 PR?
如果修复来自新增代码、测试或文档,完成本地验证后再提交 Pull Request。通常无需先关闭 Issue,可由 PR 关联问题,待合并和验证后再更新状态。
- 确认修改属于门锁项目还是 FRB 框架,阅读对应贡献说明并确认目标分支。
- Fork AtomGit 仓库,从目标分支创建独立修复分支,例如
fix/status-payload-length。 - 修改导致问题的源代码,增加能复现缺陷的回归测试。涉及 FRB API 时同步重新生成 Dart 与 Rust 绑定。
- 执行适用的 Rust、Dart 和目标平台检查。只通过主机解析器测试时,就明确写主机范围,不写“真机通过”。
- 推送到个人 Fork,在原仓库的 Pull Requests 页面选择源分支和目标分支,关联实际 Issue。
- 描述触发条件、根因、修复后的行为、验证命令和结果,根据评审意见继续修改。
- 合并后记录修复提交或版本,在受影响应用中更新并复测原场景,最后更新 Issue。
门锁协议发生变化时,按仓库约定同步协议文档、Dart Gateway、WS63 SSAP/UART 实现及 P4 协议实现。若只是把现有解析迁移到 Rust,应证明线上协议未改变,同时说明解析器有无新增校验规则。
PR 描述可以使用:
问题:哪种包或操作会触发错误。
原因:哪项字段解释或状态处理不正确。
修改:修复后有什么可观察的变化。
验证:测试命令、样本范围和实际平台结果。
关联:Issue #<实际编号或链接>。
若问题只是 SDK 配置错误,修复环境并反馈即可;若维护者已合并修复,更新版本后验证即可,不必再提交相同补丁。
3. 其他常见问题与解决方案
| 现象 | 主要检查方向 | 解决方式 |
|---|---|---|
| 原仓库执行 FRB 命令找不到配置 | 是否已新增扩展文件 | 正式仓库没有 FRB,先按扩展步骤准备 crate、依赖和配置 |
| Dart 把返回值当 Future 或对象时出错 | API 同步/异步声明 | 本文使用 frb(sync);若改为异步需 await 并处理结果顺序 |
RustLib.init() 失败 | 动态库名、架构及 HAP 打包 | 检查实际原生插件和加载配置,绑定生成成功不代表库已打包 |
| Rust 与 Dart 字段不同 | 包头/payload 偏移、字节序 | 对照协议表检查三种 sequence 和 22 字节固定部分 |
| 单测只有错误包通过 | 正常字段映射未验证 | 加入合法单人脸、零人脸和四人脸样本,逐字段断言 |
App 发现 XH-KB | WS63 是否为键盘示例固件 | 按本项目固件说明核对并更新正确门锁固件 |
配对后报 1009700099 或 -5 | 连接有效性及板端 CCCD 日志 | 对照仓库的定向兼容逻辑;其他错误或实际断线不能直接忽略 |
| 已连接但没有画面 | P4 摄像头、推理、UART JPEG | 检查 0x0C05 分片、图像大小和连续性,不只检查星闪 |
| JPEG 大于 40 KiB | WS63 缓存上限 | 调整分辨率或 JPEG 质量;App 64 KiB 缓冲不提升整条链路上限 |
| Hvigor 报 SDK 组件缺失 | SDK、Node 和 Hvigor 是否同套 | 优先使用同一 DevEco Studio 发行版的工具与 SDK |
| HAP 安装失败 | signed/unsigned、证书与设备 | 配置匹配设备的签名,安装正确签名产物 |
| 访客记录重启后消失 | 当前会话存储设计 | 当前最多 50 条内存记录,持久化需另行实现 |
七、后续方向与项目入口
当前项目已经提供摄像头、人脸检测、双芯片 UART、星闪 SSAP 与 HarmonyOS 展示链路。本文的 FRB 扩展从 STATUS 开始,将字节解析组织成可单测模块,再通过类型化 API 接入 Dart;下一步是完成目标 HAP 的真实加载与逐包比对。
从“检测到人脸”走向门锁产品,还需要身份识别、活体检测、授权判断和执行器反馈等独立能力。FRB 可以帮助整理软件边界,不能替代这些功能,也不能把检测框直接解释为开锁权限。
进一步阅读和参与项目:
更多推荐



所有评论(0)