| ✅ 负责 | ❌ 不负责 |
|---|---|
|
|
EdgeHippo = 硬件:跑协议的物理设备 EdgeMesh = 网络:设备之间怎么找到彼此、怎么搬碎片、怎么记账 EdgeMemory= 软件:碎片在板内怎么存、怎么查、怎么保持一致 EdgeMesh 不得直接访问 flash 或写库 —— 它只调用 EdgeMemory 的 em_frag_import / em_frag_export / em_sync_* 接口。
form=gamma-card)、Dev-B = β USB Dongle 形态(form=usb-dongle)。下表中的 Hub 是 EdgeMesh 协议层的中继角色(负责代持转发与账本仲裁的协议能力),不是板级定位,也不构成上下级——它与设备形态正交(见 00 号总纲 ADR-018)。
| 节点类型 | MVP 载体 | 职责 | 约束 |
|---|---|---|---|
| γ 磁吸卡形态 ( form=gamma-card) | EdgeHippo Dev-A | 持有碎片、发起查询、请求接力 | 容量小(3,700 条),通常只装专科包 |
| β USB Dongle 形态 ( form=usb-dongle) | EdgeHippo Dev-B | 持有大库(12,900 条)、承担 Hub 中转(代持转发)、账本仲裁 | MVP 只有 1 个 β 节点承担中转;多节点集群为 P2 |
| Studio (控制台) | 浏览器 | 生成碎片、触发烧录、查看账本 | 不参与运行时接力,只在配置期介入 |
┌──────────────┐
│ Hub │ EdgeHippo Dev-B (form=usb-dongle, N16R8, 12,900 条)
│ (relay) │ 代持转发 · 账本仲裁
└───┬──────┬───┘
BLE/ Wi-Fi Wi-Fi/HTTP
┌──┘ └──┐
┌─────▼─────┐ ┌────▼──────┐
│ Peer #1 │ │ Peer #2 │ EdgeHippo Dev-A (form=gamma-card, N8R8, 3,700 条)
│ Dev-A │ │ (second) │ 各装「专家记忆包」
└───────────┘ └───────────┘
└────── UART1 备用互联 ──────┘
现有 link_mgr 已实现 1 usb-dongle + 2 gamma-card 的 BLE 互联拓扑(原记作「1 gateway + 2 edge」,属板级角色表述),EdgeMesh 直接复用其链路管理,只替换上层语义。
| 承载 | 速率(实测量级) | 适用 | G5 判据 | 限制 |
|---|---|---|---|---|
| Wi-Fi HTTP | 最快(局域网) | 灌库、大碎片传输、Studio 连接 | ≤ 60 s (12,000 条) | 需同一局域网;须 CORS |
| USB CDC (WebUSB / Serial) | 12 Mbps Full-Speed,实际 bulk 有效约 0.5–1 MB/s | 在线灌库、调试、eme | ≤ 90 s | 需驱动(CDC 免驱);浏览器访问不了 MSC |
| USB MSC | OS 层文件拷贝 | 离线灌库、离线投递接力 | ≤ 60 s | 非浏览器可达;需 PHY 决策(01 号分册第 6 章) |
| 串口 UART0 (921600) | 7.9 MB 理论 86 s,含板端写入约 2–4 min | 首刷、救砖、无 USB 场景 | ≤ 240 s | 不要为凑 60 s 砍掉它——最可靠。要求:进度清晰 + 断点续传 |
| BLE | 最慢(NimBLE 实测远低于 Wi-Fi) | 发现、小消息、控制面 | 不用于灌满库 | 只传控制消息与单条记忆;host 任务栈 ≥ 8192 |
| UART1 (GPIO17/18) | 中 | BLE 不可用时的降级互联 | — | 需交叉接线 |
em_frag_import 不感知承载。
格式:EME-<MAC 后 3 字节大写 HEX>
例: EME-21E980(Dev-B,MAC 14:C1:9F:21:E9:80)
EME-71FAC8(Dev-A,MAC 44:BD:8D:71:FA:C8)
旧前缀 EMGW- 在 MVP 期间仅做兼容识别,不再新发。em_dev_is_placeholder_id() 已有占位 ID 检测逻辑,须同步更新前缀判断。
每个设备周期性广播自己的碎片目录摘要,不是全量内容:
{
"msg": "mesh.advert",
"body": {
"dev": "EME-21E980",
"form": "usb-dongle", /* 板级形态标识(gamma-card / usb-dongle),非角色 */
"cap_kb": 12900, /* 容量上限 */
"used_kb": 8412, /* 已用条数 */
"frags": [ /* 只列摘要,不列内容 */
{"id":7,"name":"docs-core-v1","scene":3,"ver":3,"count":6000},
{"id":9,"name":"expert-pack-v3","scene":2,"ver":3,"count":1800}
],
"bearers": ["wifi","ble","usb"],
"uptime_s": 12345
}
}
mesh.advert(BLE 广播包 / HTTP mDNS / UDP 组播)link.scan / hub.discover 命令返回邻居表所有 EdgeMesh 消息(无论承载)共用同一 envelope。BLE 上用精简二进制变体,HTTP / 串口 / USB 用 JSON。
{
"v": 1, /* 协议版本 */
"src": "EME-71FAC8", /* 源设备 ID */
"dst": "EME-21E980" | "*", /* 目的,* = 广播 */
"msg": "mesh.query", /* 原语名 */
"seq": 1234, /* 单调序号,用于去重与应答配对 */
"ttl": 4, /* 跳数上限,防环路 */
"ts": 1770000000000, /* 毫秒时间戳 */
"tok": "…", /* 配对 token(配对后必填) */
"body": { … } /* 原语专属 */
}
| 字段 | 规则 | 失败处理 |
|---|---|---|
seq | 每设备单调 +1;收到重复 seq 直接丢弃(防重放与环路) | 静默丢弃 |
ttl | 每转发一次减 1;为 0 时丢弃 | 静默丢弃 |
tok | 未配对设备只能发 mesh.advert 与 mesh.pair | 返回 ERR_UNAUTHORIZED |
ts | 与本地时钟差 > 5 min 时拒收(防重放) | 返回 ERR_CLOCK_SKEW |
{ "v":1, "src":"EME-21E980", "dst":"EME-71FAC8",
"msg":"mesh.result", "seq":1234, "ack_seq":1234,
"body":{ "code":0, "msg":"ok", "data":{ … } } }
/* 错误码 */
0 OK
1 ERR_BAD_REQUEST 参数错
2 ERR_UNAUTHORIZED 未配对 / token 无效
3 ERR_NOT_FOUND 碎片不存在
4 ERR_QUOTA_EXCEEDED 配额不足
5 ERR_BUSY 正在导入/导出
6 ERR_CLOCK_SKEW 时钟偏差过大
7 ERR_STORAGE_FULL 容量不足
8 ERR_CRC 数据校验失败
复用现有 /api/mesh/* 端点与 mesh.* 命令,消息名保留,字段从「算力竞标」重定义为「碎片接力」(ADR-011)。
| 原语 | 旧语义 → 新语义 | body | 返回 |
|---|---|---|---|
mesh.query |
算力询价 → 查谁有我需要的知识 | {scene, tags[], vec_b64?, k, need_count} |
{candidates:[{dev, frag_id, ver, count, quota}]} |
mesh.bid |
算力报价 → 响应「我有,代价是 N 配额」 | {frag_id, ver, count, bytes, quota, bearer[]} |
— |
mesh.request |
任务派发 → 请求具体碎片(可分块) | {frag_id, ver, chunk_off, chunk_len} |
接受或拒绝(含原因) |
mesh.result |
任务结果 → 返回碎片数据块 | {frag_id, chunk_off, total, crc32, data_b64} |
接收方逐块校验 |
mesh.award |
结算给 winner → 记账:配额从请求方转给提供方 | {frag_id, bytes, quota, from, to, ts} |
{ledger_seq} |
mesh.ledger |
(已有)→ 查询本地账本 | {since_seq?, peer?} |
{entries:[{seq, from, to, frag_id, bytes, quota, ts}]} |
Peer(Dev-A, γ 磁吸卡形态) Hub(Dev-B, β USB Dongle 形态)
|--- mesh.query {scene:2} ------->| 我要野外巡检的碎片
|<-- mesh.bid {frag:9, quota:12} -| 我有 expert-pack-v3,12 配额
|--- mesh.request {frag:9} ------>| 请给我
|<-- mesh.result chunk 0/87 ------|
|<-- mesh.result chunk 1/87 ------| 4 KB 分块 + CRC32
| … 断点续传 … |
|--- mesh.award {quota:12} ------>| 记账:我给你 12 配额
|<-- mesh.result {code:0} --------|
| |
| em_frag_import → 事务提交 → LED 蓝快闪结束 → 绿常亮
em_frag_import 事务内完成。任一分块 CRC 失败 → 重传 → 三次失败则 abort → 已灌入的记忆必须完好如初。
| 模式 | 名称 | 流程 | 适用 | 约束 |
|---|---|---|---|---|
| M1 | 直连取块 Direct |
请求方与提供方同时在线,走上述六原语时序 | 同局域网 / BLE 可达;小到中等碎片 | 默认模式 |
| M2 | Hub 中转 Relay |
提供方离线,但其碎片已托管在 Hub。请求方向 Hub 取,Hub 代记双份账(给原提供方 + 给 Hub) | 移动设备、间歇在线 | Hub 须持有该碎片的完整副本与 owner 字段 |
| M3 | 离线投递 Sneakernet |
用 USB MSC 把 .emf 拷到设备;账本靠 .emf 内嵌的 quota 字段与回执文件在下一次联网时对账 |
完全无网环境(野外巡检 S2 的核心) | 账本最终一致;对账时以双方 ledger 并集为准,重复条目按 frag_id+seq 去重 |
/* 投递方生成 .emf 时同时生成 .emr(回执) */
{
"v":1,
"from":"EME-21E980",
"to":"*", /* 未知目的,联网后补 */
"frag_id":9, "name":"expert-pack-v3", "ver":3,
"bytes":1188000, "quota":36,
"delivered_ms":1770000000000,
"crc32":"0x8A3F2C11"
}
/* 接收方联网后把 .emr 回传给 Hub,Hub 合并进账本 */
| 属性 | 规定 |
|---|---|
| 名称 | 配额(quota),单位「点」。设备间内部记账单位 |
| 可兑换性 | 不可兑换法币、不可兑换任何虚拟资产、不可转让给第三方 |
| 提现 | 不存在。没有任何提现通道,也不得在 UI 中出现该词 |
| 交易场所 | 不存在。不得提供任何撮合、挂牌、报价界面 |
| 用途 | 仅用于设备间协作的计量与反滥用(防止某台设备无限索取碎片) |
| 初始分配 | 每台设备出厂固定额度,不得增发 |
{seq, from, to, frag_id, bytes, quota, ts},seq 设备内单调ERR_QUOTA_EXCEEDED,不得降级为「先给数据后补账」store.map 的同源输出(02 号分册 6.2 节)禁止出现:钱包、币价、代币、代币化、提现、收益、挖矿、算力市场、交易、撮合、上币、持仓、K 线、DePIN、RWA。
可用表述:配额、协作计量、记账、点对点同步、知识接力。
| 对象 | 一致性 | 机制 |
|---|---|---|
| 板内库 | 强一致(ACID) | WAL + CoW + 原子提交(02 号分册 3.3 节)。不允许最终一致 |
| 跨设备碎片 | 最终一致 | 版本向量 (frag_id, name, ver);高 ver 胜,同 ver 比 created_ms |
| 账本 | 对账后一致 | 双向条目并集去重;误差必须为 0 |
| 冲突 | 规则 | 例外 |
|---|---|---|
| 同名碎片不同版本 | 高 ver 胜;同 ver 取 created_ms 大者 | OVERWRITE_SAME_NAME 未置位时直接拒绝 |
| 同 ID 不同内容 | 取 ts_ms 大者;旧条目标记 CONFLICTED 并降 prio | PINNED 条目不参与覆盖 |
| 记忆条目语义重复 | 余弦 > 0.95 → 合并(hit_count 累加) | 不同 scene 不合并 |
| 账目重复(M3 回执) | 按 frag_id + seq 去重 | — |
| 项 | MVP 方案 | 说明 |
|---|---|---|
| 配对 | 首次连接需 mesh.pair,token 存入 NVS | 未配对时 LED 白双闪 |
| 消息鉴权 | 配对后所有消息带 tok | 未配对只放行 mesh.advert / mesh.pair |
| OTA 鉴权 | token emgw-ota-demo | MVP 后必须改为每设备独立 token |
| 重放防护 | seq 单调 + ts 偏差 ≤ 5 min | 返回 ERR_CLOCK_SKEW |
| 滥用防护 | 配额 + 每设备速率上限 | 返回 ERR_QUOTA_EXCEEDED |
| 数据加密 | MVP 不加密(局域网内明文) | P2 评估 BLE 链路加密与 TLS |
| 现有 | 动作 | 说明 |
|---|---|---|
/api/mesh/query | 改字段 | 入参从算力规格改为 {scene, tags, vec_b64, k} |
/api/mesh/bid | 改字段 | 报价改为 {frag_id, ver, count, bytes, quota} |
/api/mesh/request | 改字段 | 支持分块 chunk_off / chunk_len |
/api/mesh/result | 改字段 | 返回碎片数据块 + CRC32 |
/api/mesh/award | 改语义 | 从「结算给 winner」改为「配额记账」 |
mesh.query / mesh.ledger | 保留 + 扩字段 | 命令名不变 |
link_mgr(BLE 1 usb-dongle + 2 gamma-card) | 直接复用 | 链路管理不改 |
Kconfig 板级选项EMGW_ROLE_EDGE / EMGW_ROLE_GATEWAY | 改名 | 改为 EMGW_FORM_GAMMA_CARD / EMGW_FORM_USB_DONGLE(二选一不变;ADR-018) |
运行时角色字符串edge / gateway | 改值 | 改为 gamma-card / usb-dongle;mesh.advert 字段名 role → form(ADR-018) |
link.sync / hub.* | 保留 | M2 中转基于此 |
em_dev_unique_id() | 改前缀 | EMGW- → EME-,保留旧前缀兼容识别 |
| 新增 | — | mesh.advert / mesh.pair / /api/mesh/sync |
完整用例见 05 号分册 TC-M-*(12 条)。本节列出覆盖矩阵,便于查漏补缺。
| 能力 | 用例 | 判据 |
|---|---|---|
| 发现 | TC-M-01/02 | 两板 30 s 内互相可见;离线设备 120 s 后从邻居表消失 |
| M1 直连接力 | TC-M-03/04/05 | 完整六原语时序跑通;分块 CRC 全过;中断后续传成功 |
| M2 Hub 中转 | TC-M-06/07 | 源离线时仍可取到;账本记双份 |
| M3 离线投递 | TC-M-08/09 | MSC 拷入后可用;联网对账误差 0 |
| 账本 | TC-M-10 | 双向对账误差 = 0(G9) |
| 失败路径 | TC-M-11 | 接力失败后已有库完好如初 |
| 配额 | TC-M-12 | 配额耗尽返回 ERR_QUOTA_EXCEEDED,不得降级放行 |