# ark_softbus **Repository Path**: xw19981010/ark_softbus ## Basic Information - **Project Name**: ark_softbus - **Description**: ark softbus是一个用于分布式设备的软总线组件,用于解决分布式设备的自组网与控制还有集群计算,为未来分布式计算做好准备 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-10-07 - **Last Updated**: 2026-10-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ark_softbus **[简体中文]** | [English](README_en.md) 一个下午就能接上的跨平台软总线:主题发布 / 订阅 + 设备发现,再往上是一层**控制面**——RPC、能力查询、任务提交与故障重派,以及一个能让大模型直接驱动总线的 MCP 节点。同一份核心跑在 Cortex-M 上,也跑在你主机的单元测试里。 没有 RTOS 头文件,没有堆,不用 `malloc`、`pthread`、`errno`。核心由几个 `.c` 文件组成,所有碰真实硬件的东西 (时钟、临界区、串口 / 网络口)全部推到 HAL 与传输适配后面。 ```c #include "ark_bus.h" #include "ark_bus_transport.h" static ark_bus_t bus; void on_temp(const char *topic, const uint8_t *payload, uint16_t len, void *user) { /* payload / len 是另一台设备发来的原始字节,仅在回调期间有效 */ } ark_bus_init(&bus, &uart_adapter); /* uart / loopback / tcp / udp */ ark_bus_subscribe(&bus, "sensor/temp", on_temp, NULL); ark_bus_start(&bus, 0x1234 /* self id */, 0x01 /* device type */, 0x01 /* caps */); for (;;) { uart_pump(); /* 把收到的字节喂给传输层 */ ark_bus_poll(&bus); /* 服务发现 / 心跳 / QoS 重传 */ } ``` 整个思路就这一句:中间是一个小、可预期的核心,所有让它在不同平台上跑起来的东西全推到两个接口后面。 ``` 应用 | publish / subscribe / publish_to / poll / start / stop v ark_softbus 核心 ..... 主题表、设备表、QoS 会话、发现、心跳(本仓库) | +--> transport ..... 传输适配:uart、loopback、tcp、udp | +--> HAL ........... 时钟、临界区、随机数 ``` ## 五条承诺 这是本库立下并守住的规则。哪个改动破坏了其中一条,那个改动就是错的。 1. **零依赖。** 只 include `` 和 ``。不用 libc 的字符串函数,连 `memcpy` 都不用—— `src/ark_bus_util.c` 里是本地的 BE 编解码与内存助手。这里没有一处链接 libc。 2. **无堆。** 每张表都是静态定长数组。`ARK_BUS_MAX_TOPICS` 个主题、`ARK_BUS_MAX_DEVICES` 台设备、 `ARK_BUS_QOS_MAX_SESSIONS` 个在途会话,这就是上限。表满返回 `ARK_BUS_E_FULL`,不会自己长大。 一个 `ark_bus_t` 就是个普通的值,能放 `.bss`,也能放测试里的栈上。 3. **大端在线格式,固定帧头。** 19 字节头的前 11 字节就够定出整帧长度,配合 2 字节 CRC16 让流式接收器 能在任意字节流上重同步——坏魔数重启扫描、半帧丢弃,而不是把后面那帧好的一起吞掉。 4. **主题名就是身份。** 线上流转的是主题名的 15 位哈希(`topic_id`),不是"注册顺序"。两台设备各自按名字 注册,编号天然一致,无需协商索引。 5. **平台是插进来的。** 核心永远不知道底下是 UART 还是 TCP。时钟与临界区来自 `ark_bus_hal_t`, 收发来自 `transport_adapter_t`;换平台就是换这两个实现,核心一行不动。 ## 目录布局 ``` include/ark_bus.h 公开 API——生命周期、pub/sub、poll、统计 include/ark_bus_config.h 上限与超时;放到 include 路径更前面即可覆盖 include/ark_bus_protocol.h 线帧布局、消息类型、标志、能力位、编解码、流式接收器 include/ark_bus_rpc.h RPC 层:方法注册、请求 / 应答、超时 include/ark_bus_caps.h 能力查询与 DESCRIBE 自述 include/ark_bus_task.h 任务引擎:提交 / 状态 / 结果 / 故障重派 include/ark_bus_types.h 状态码、回调、topic / device / stats 结构 include/ark_bus_hal.h HAL 接口 include/ark_bus_transport.h 传输接口 + uart / loopback / tcp / udp 声明 src/ark_bus_core.c 主题表、发布订阅、dispatch、poll、统计、锁深度 src/ark_bus_frame.c CRC16、编码、解码、流式接收器 src/ark_bus_discovery.c DISCOVER / DISCOVER_REPLY / HEARTBEAT 与离线判定 src/ark_bus_qos.c QoS1 会话重传 / ACK / 超时 src/ark_bus_rpc.c RPC:请求槽表、方法表、超时、应答分发 src/ark_bus_caps.c DESCRIBE 与按能力查节点 src/ark_bus_task.c 任务状态机、幂等缓存、重试与改派 src/ark_bus_stream.c 数据面:分块传输、累积应答、缺口重传 src/ark_bus_hal.c HAL 安装与包装 src/ark_bus_util.c 本地内存 / 字符串 / 大端助手 src/transport/ uart、loopback、sock(TCP/UDP) 三个传输适配 ports/linux/ POSIX HAL(单调时钟 + pthread mutex) ports/arkrtos/ Ark RTOS 端口(三个钩子接进内核) ports/baremetal/ 裸机端口:SysTick 毫秒时钟 + PRIMASK 临界区,零 CMSIS、零 RTOS examples/ hello_bus_linux(双节点回环)、hello_bus_mcu(单节点骨架) tests/ 主机测试:2328 项,无框架 sim/ 多节点仿真:3 节点共享介质,289 项检查(确定性,含数据面丢帧重传、环形集合通信、张量并行 MLP / decoder 块 / 整模型前向、远程推理与动态成员) sim/bench.c 算力损失基准:编码 / 解码 / 往返的 CPU 代价(宿主实测) tools/footprint.sh 体积与依赖报告,兼功能开关闸门:size + nm tools/bus_bridge/ 串口 ↔ TCP 哑转发桥(接 MCU 段) tools/demo/multiproc/ 多进程控制面 demo:1 coordinator + 3 worker,中途杀 worker tools/demo/matmul/ 分布式矩阵乘 demo:真算矩阵乘、按列分片到多节点,结果与单机串行逐元素一致 mcp/ MCP 节点:把总线暴露给大模型(Python,另见其 README) CMakeLists.txt / platform/ 交给下游的构建文件 docs/ 文档目录(中英双语,`*.en.md` 为英文):架构、协议、移植、控制面、数据面、集合通信、推理适配、远程推理、可靠性、工具接口、认证、网状路由、共识、集群运维 ``` ## 四条主线 | 能力 | API | 说明 | |---|---|---| | 发布 / 订阅 | `ark_bus_publish` / `ark_bus_subscribe` / `ark_bus_unsubscribe` | 同主题的本地订阅者收到回调;带 QoS1 时也走线 | | 定向发布 | `ark_bus_publish_to` | 只发给某一台设备;可与 QoS1 组合,重传至 ACK 或超限 | | 设备发现 | `ark_bus_announce` + `ark_bus_poll` | 上电广播 DISCOVER、应答 DISCOVER_REPLY、周期心跳;超时判离线 | | QoS1 | `ARK_BUS_QOS_ENABLED` | 在途会话表 + 定时重传 + ACK 收尾;广播不带 QoS1 | `ark_bus_poll(&bus)` 是唯一的服务入口:它推进心跳、清理超时设备、驱动 QoS 重传,也在这里让 RPC 超时、让任务引擎改派丢失的任务。主循环里按需调用即可, 阻塞与否由 HAL 与传输层决定——核心自己从不 sleep。 ## 控制面 数据面管「怎么把字节送过去」,控制面管「让谁去做、做得怎么样」。三者叠在核心之上,只用到公开 API,各自一个开关: | 能力 | API | 说明 | |---|---|---| | RPC | `ark_bus_rpc_request` / `ark_bus_rpc_call` / `ark_bus_rpc_register` | 请求 / 应答,搭在定向发送(DIRECT)之上,天然继承 QoS1 重传 | | 能力与自述 | `ark_bus_device_caps` / `ark_bus_find_by_cap` / `DESCRIBE` | 每个节点在发现载荷里就带着能力掩码;不必问就知道它能干什么 | | 任务引擎 | `ark_bus_task_submit` / `task_status` / `task_result` / `ark_bus_task_on_run` | 提交任务、跟踪状态、失败后**改派到另一个 worker**、结果带回 | | MCP | `mcp/server.py` | 把总线暴露成一组工具给大模型(只读默认开,动作要显式开启) | 一条任务就是一次对 worker 的 `TASK_RUN` RPC 调用。worker 侧的任务体由 `ark_bus_task_on_run()` 装上,它带一层幂等缓存——同一个 `task_id` 重复送达只算一次, 所以底层「至少一次」的投递对上层是安全的。重派时引擎会避开已经试过的 worker (按位图记住整个已试集合),因为**心跳比 RPC 超时慢**:死掉的 worker 在若干秒内 仍然显示 ONLINE,只有记住全部已试者才能保证改派落到活节点上。 完整设计、线格式与 M1 的边界见 [docs/control-plane.md](docs/control-plane.md)。 ```c /* 控制面一瞥:注册一个方法、提交一个任务、等结果 */ ark_bus_rpc_register(&bus, 0x8001, on_work, NULL); /* worker 侧 */ ark_bus_task_submit(&bus, ARK_BUS_M_TASK_RUN, params, sizeof params, ARK_CAP_COMPUTE, 0 /* 自动挑 */, on_done, NULL); ``` ## 状态码 所有错误都是负数,且都在 `ark_bus_types.h` 里有说明: | 错误码 | 含义 | |---|---| | `ARK_BUS_OK` | 成功 | | `ARK_BUS_E_INVAL` | NULL、空主题名、非法参数 | | `ARK_BUS_E_NOMEM` | 没有存储安放新条目 | | `ARK_BUS_E_FULL` | 主题表 / 设备表 / QoS 会话表已满 | | `ARK_BUS_E_NOTFOUND` | 主题未注册或设备不存在 | | `ARK_BUS_E_NOSYS` | 该传输 / 平台未实现此调用 | | `ARK_BUS_E_AGAIN` | 稍后重试(非阻塞路径) | | `ARK_BUS_E_FORMAT` | 帧头非法(版本 / 魔数 / 长度) | | `ARK_BUS_E_CRC` | 校验失败 | | `ARK_BUS_E_STATE` | 当前状态不允许这个调用 | | ... | 完整清单见 `ark_bus_types.h` | 它们刻意**不是** `errno` 值:本库运行在 `errno` 不存在的地方,而且它绝不能在一个有 `errno` 的主机上改变含义。 ## 测试 ```sh sh tests/run_host_tests.sh # 核心 + RPC/任务 + 传输 + 数据面 + 集合通信 + 推理 + 整模型 + 远程推理 + 工具接口 + 可靠性 + 推理补强 + 帧认证 + 载荷加密 + 防重放 + 握手/会话 + 分词 + 网状路由 + 共识(Raft) + 集群运维(签名固件):2546 项,退出码 = 失败项数 sh sim/run_sim.sh # 多节点仿真:289 项,退出码 = 失败项数 sh tools/demo/multiproc/run_demo.sh # 多进程控制面 demo(真起进程,中途杀 worker) sh tools/demo/matmul/run_demo.sh # 分布式矩阵乘:多节点分片计算,结果与单机串行逐元素一致 sh mcp/run_e2e.sh # MCP 端到端:Python 节点驱动真实 C 节点,36 项 ``` 一个框架都没有:在目标板上跑的代码,在同一份主机测试里跑。测试用 `tests/mock/` 里可控的 tick、锁与 Ark RTOS 钩子把时间推快,覆盖编解码(含故意损坏的帧与半帧重同步)、主题注册、发布 / 订阅、定向发布、 QoS1 重传与 ACK、发现与心跳离线、UART 逐字节喂入、HAL 配平,以及 RPC 寻址(发给别人的请求不能被自己执行)、 任务提交 / 改派 / 结果回收、以及数据面(大于一帧的对象分块传输:逐字节还原、缺口拒收后可恢复、重复片幂等、超限对象诚实拒收、超时终止)。 `sim/` 用一台纯内存的共享总线把**多节点**场景跑起来——三个节点互相发现、广播、定向 QoS1 丢帧重传、 噪声重同步、节点静默后判离线再复活,以及数据面在丢失副本的介质上靠重传把对象完整送达(旁观节点不得误收)。它只用 gcc,不联网、不起线程,虚拟时钟让心跳与超时在一瞬间发生。 细节见 [sim/README.md](sim/README.md)。 ## 平台与移植 核心与平台之间只有两个接口:`ark_bus_hal_t`(毫秒时钟 + 加锁 / 解锁)和 `transport_adapter_t`(收 / 发)。 把这两个实现出来,核心一行都不用改。仓库里已经给了四种落地: - **Linux / 主机**:`ports/linux/` 提供单调时钟与 `pthread_mutex` 临界区;`tests/` 与 `examples/hello_bus_linux` 用它。 - **Ark RTOS**:`ports/arkrtos/` 把三个钩子(毫秒时钟、临界区进入 / 退出)接到内核;`README` 里有接线说明。 - **裸机(无 RTOS、零 CMSIS)**:`ports/baremetal/` 就是最常见的“一个主循环 + 一个节拍中断”形态——时钟由 `SysTick_Handler` 里调 `ark_bus_bare_tick_isr()` 推进,临界区直接保存 / 恢复 `PRIMASK`(不依赖任何 CMSIS 头), `main` 里把 `ark_bus_poll()` 放进循环、UART 中断只负责喂字节。接线示例见 [ports/baremetal/README.md](ports/baremetal/README.md)。 - **STM32 / 任意 MCU**:照 `ports/baremetal/` 抄即可;换时钟源或换串口,改的也只是这个端口文件。 **体积与零依赖是有据可查的**,不是口号: ```sh sh tools/footprint.sh ``` 它用宿主编译器把核心九个 `.c` 编出来,`size` 报体积、`nm` 逐一核对未定义符号。当前结果(gcc -Os,宿主, 仅供参考):**`.text ≈ 13.4 KB`、`.data` 4 B、`.bss` 0 B,外部符号为 0**——没有一个 libc、malloc 或浮点 运行时符号。这份结论与平台无关(换编译器仍应为 0),是“零依赖”这条承诺的硬证据。 它同时是一道**功能开关闸门**:把 `ARK_BUS_RPC_ENABLED=0 / ARK_BUS_TASK_ENABLED=0` 编一遍, `nm` 必须看不到 `ark_bus_rpc_*` / `ark_bus_task_*` 符号,体积也要掉下去(实测 13.7 KB → 7.6 KB)。 关掉的功能不能在镜像里留下痕迹——“默认开的特性,关掉应当零代价”这句话是可执行的。 细节见 [docs/porting.md](docs/porting.md)。 ## 协同计算的算力损失 把活儿分给几台芯片,代价是它们每交换一条消息就有一部分 CPU 花在总线本身,而不是花在问题上。 `sim/bench.c` 用**和 MCU 上同一份核心**在宿主上把这份代价量出来: ```sh sh sim/run_bench.sh ``` 它用 gcc -O2 编译,测几条关键路径——CRC、帧装配、`publish`(查表 + 装配 + 发送)、`decode` (校验 + 解析 + 回调)、以及 A↔B 往返——再换算成“一个既发又收的节点,在给定消息率下吃掉多少 CPU”。 一次代表性实测(64 字节载荷,宿主 x86-64,200000 次取三次最小值;同机多次运行抖动约 ±15%): | 量 | 数值 | |---|---| | 一帧 CRC-16(275 字节) | ≈ 2.6 µs | | 帧装配(不含查表 / 发送) | ≈ CRC 的 1.0 倍 | | `publish`(查表 + 装配 + 发送) | ≈ CRC 的 1.0 倍 | | `decode`(校验 + 解析 + 回调) | ≈ CRC 的 0.9 倍 | | 发一条 + 收一条(同一节点) | ≈ 9–10 µs | | 10% CPU 能承受的消息率 | ≈ 1 万条 / 秒 | | 一条消息 ≈ 多少个 128 抽头定点乘累加 | ≈ 150–190 次 | 结论很干脆:**代价几乎全在 CRC 上**。主题查表(几纳秒)与传输分发(一次函数指针调用)相对 CRC 可忽略, 所以“用名字当身份”的哈希查表并不构成负担;真正吃 CPU 的是逐位 CRC。要提吞吐,先换 CRC 实现(查表 / 半字节), 而不是去优化发布包装。 **一个必须说清的测量陷阱**:逐位 CRC 的内层分支依赖数据。若反复喂同一帧,CPU 的分支预测器会记住这个 模式,测出来的速度会比真实流量快约 4 倍——一个真实流量永远吃不到的漂亮数字。因此基准里每个操作**每次 迭代都改动一个输入字节**(`g_epoch`),让数字对应真实的、变化的数据。若你在别处看到本项目一个“更漂亮” 的旧数字,多半就是踩了这个坑。 ⚠️ 这些是**宿主**数字,不是 Cortex-M 周期数。载荷尺寸之间的比例与“CRC 主导”这个形状会迁移;绝对值不会。 换 `armclang` / `arm-none-eabi` 重跑同一份 `bench.c`,才是目标板上的周期数。 ## 构建 **主机测试(无 cmake,一份 Makefile):** ```sh make -C tests ./tests/ark_bus_tests ``` **交给下游的 CMake:** ```sh cmake -S . -B build -DARK_SOFTBUS_PLATFORM=linux cmake --build build ``` ## 状态 版本 0.1.0(尚未发布到任何包仓库)。 | 部分 | 状态 | |---|---| | 核心(frame / core / discovery / qos) | 完成,主机 2328 项检查全绿(tests/Makefile 默认开启的闸门;逐特性的体积开关见 `tools/footprint.sh`) | | 控制面(RPC / caps / task) | 完成;主机 2328 项、仿真 289 项、多进程 demo 与 MCP 端到端均过 | | 数据面(分块传输) | 完成;对象大于一帧时分块发送、远端累积应答重组,缺口可恢复、重复幂等、超限诚实拒收;关闭宏后零体积零符号(footprint 闸门)。集合通信(all-reduce / broadcast / reduce / all-gather / gather,环形算法)已完成,叠加在分块传输之上。见 [docs/data-plane.md](docs/data-plane.md)、[docs/collectives.md](docs/collectives.md) | | 推理适配(M3.1 / M3.2) | 完成;算子后端 vtable(GEMM / SiLU / RMSNorm / add / softmax / argmax / **attn**)+ plan 驱动的张量并行执行器 + MLP 块 + **头并行 attention 子块** + **完整 decoder 块**(rmsnorm→attn→rmsnorm→mlp,两次 all-reduce,12 步),可移植 f32 参考后端零 libm;分布结果与单机参考在容差内一致、`E_BUSY`/`E_NOSYS`/`E_INVAL` 边界有测;关闭宏后零体积零符号(footprint 闸门)。见 [docs/inference.md](docs/inference.md) | | 整模型前向(M3.2b) | 完成;在 decoder 块之上叠加**整个 decoder-only 模型**——vocab 并行 embedding 查表 + `nlayers` 层堆叠 + final norm + vocab 并行 logits + 分布式 argmax(topk1→allgather→merge,并列取最低 rank);`ark_bus_infer_plan_model` 一步生成 `7+12*nlayers` 步的 plan,新增 `EMBED` 内核与 `ark_bus_infer_run_steps`(受限步列表运行时);每 rank 的 logits 分片与复制后的 final hidden 对单机参考**逐行**比对,argmax 与单机一致;关闭宏后零体积零符号(footprint 闸门)。见 [docs/inference.md](docs/inference.md) | | 远程推理(M3.3) | 完成;把 plan(算子步列表)经 RPC 发给对端执行——张量按 handle 驻留对端、结果按值随答复返回,分派不可携带集合通信与 `CALL`(`E_NOSYS`);答复容不下结果时,开了 `ARK_BUS_INFER_REMOTE_STAGE_ENABLED` 则**暂存分块回传**(结果按 handle 暂存、分块拉取),关时退回报 `E_NOMEM` 绝不截断;编解码 / 往返 / 错误面有测,关闭宏后零体积零符号(footprint 闸门)。见 [docs/remote-inference.md](docs/remote-inference.md) | | 推理补强(M3 补强) | 完成;在推理适配之上补齐三件可开关能力——**decode 步 KV 缓存**(`ATTN_CACHE` 算子 14,把新 token 的 K/V 追加进调用方缓存、只 attend 位置 ≤ 当前 query 的 token,越界 `E_INVAL` 且不推进 `len`)、**int8 权重后端**(`QGEMM` 算子 15,对称 per-tensor q8,行内反量化,误差有界——反量化 ≤ scale/2、qgemm 对反量化矩阵的 f32 结果 ≤ `0.5*scale*Σ|a|`,三节点 MLP q8 权重对 f32 参考实测 0.96%)、**采样器**(贪心 / top-k / 温度 / 核采样,做成 `CALL` 步,无堆无全词表排序,分布只在 top-k 候选内且此取舍写进头文件)。三者均默认关,各自单独开关(`ARK_BUS_INFER_KV_ENABLED` / `_QUANT_ENABLED` / `_SAMPLING_ENABLED`),默认构建 `.text` 与符号集与旧版逐字节一致(footprint 闸门含三组 `[kv-on]`/`[quant-on]`/`[samp-on]`)。见 [docs/inference.md](docs/inference.md) | | 工具接口(M5) | 完成;节点把动作登记为「名字 + 摘要 + 参数签名 + 处理器」,签名是极简文法(`name:type`,由宿主展开成模型读的 JSON Schema,设备不背 JSON);策略**默认拒绝**(无策略即 `E_DENIED`,allow-mask 位图 + 固定窗口限流),高风险工具被**挂起等人工批准**(缓存请求 → `E_APPROVAL` + token → `TOOL_APPROVE` 才执行,逾 `APPROVAL_TTL_MS` 过期),每次决策落固定审计环。五个方法 `TOOL_LIST` / `TOOL_CALL` / `TOOL_APPROVE` / `TOOL_AUDIT` / `TOOL_RESULT` 经 RPC,且须显式 `ark_bus_tool_enable()` 才可达;参数/结果走显式值文法(`count` + `type`/`len`/`bytes`,标量小端),handler 一律返回 `OK`、把真实结果放进 `astatus` 字节(否则被 RPC 层清空 body)。M5.3 更细的安全边界:**每调用方策略**(caller override,带独立限流窗口,replace 而非 merge)、**审批人身份**(`ark_bus_tool_set_approvers`,非列出节点批准得 `E_DENIED` 且不消耗 token)、**结果分块**(结果超一帧则暂存并回 `STAGED` + total + handle,`TOOL_RESULT` 仅 owner 可拉、非 owner `E_DENIED`);`ARK_BUS_TOOL_STAGE_MAX=0` 时整条分块路径编译掉。关闭宏后零体积零符号(footprint 闸门,含 `[no-tool]`、`[no-stage]`)。见 [docs/tool-interface.md](docs/tool-interface.md) | | 可靠性(M4.1–M4.4) | 完成;**动态成员**(`ark_bus_leave` 广播 LEAVE 即时移除、`JOIN`/`LEAVE`/`OFFLINE`/`REAPED` 成员回调、可选收割窗口,默认 0=永不收割;删除走 swap-remove 并同步交换任务「已试过」掩码位);**流控背压**(只缓冲无重传层的流量,短写视为拥塞、整帧入队不半写,队满回 `E_AGAIN`,TTL 丢弃计数,`FLOW_BUSY`/`FLOW_READY` 暂停定向流量,`ARK_BUS_FLOW_ENABLED=0` 时逐字节等同旧行为);**任务检查点**(在途任务写入调用方缓冲、重启后收编为 QUEUED,回调/req_id/tried_mask 明确不序列化,`ARK_BUS_CHECKPOINT_ENABLED=0` 时零字节);**桥硬化**(每方向有界 FIFO 重试队列 + 水位 `peak` + 溢出/半帧计数)。开关默认关,闸门 `[flow-on]`/`[chk-on]` 证明「开有符号、默认无符号」,`.text` 1828 B / 1292 B(开)。见 [docs/reliability.md](docs/reliability.md) | | 分布式计算 demo | 完成;3/5/8 节点分片矩阵乘,激活 A(512 B)走数据面分块、触发 RPC 恒为 12 B,拼装结果与单机串行逐元素一致(含 `--corrupt` 负向对照),README 见 `tools/demo/matmul/` | | MCP 节点 | 完成;Python 节点驱动真实 C 节点 36 项全过(含工具面与分块结果拉取),README 见 `mcp/` | | 传输(uart / loopback / tcp / udp) | 完成;UDP 已实现(`ark_bus_transport_udp_init`)并在主机实测;沿用帧自身 CRC,不叠加数据报级重传(有向路径的可靠性交给 QoS1 / 数据面) | | 远程订阅(`ARK_BUS_REMOTE_SUB_ENABLED`) | 完成;hub 转发远端 `SUBSCRIBE`/`UNSUBSCRIBE` 给它被告知的订阅者、对端离开即忘;关闭时行为与旧版逐字节一致,关闭宏后零体积零符号(footprint 闸门) | | 网状路由(`ARK_BUS_ROUTE_ENABLED`) | 完成;在设备表之上加小型**距离向量路由器**,让节点把帧送到数跳以外的对端——直连邻居免费、多跳靠 `ROUTE_ADV`(0x61)学习(仅更短路径才替换)、投递用带 TTL 的 `ROUTE`(0x60)封套逐跳转发、终点剥封套交公共 `ark_bus_dispatch` 分发;尽力而为、无堆无 libc、定长表(8×16 B + 计数器 = 144 B);关闭宏后零体积零符号(footprint 闸门 `[route-on]` / 默认档 `[full]` absent)。见 [docs/routing.md](docs/routing.md) | | 共识 Raft(`ARK_BUS_RAFT_ENABLED`) | 完成;在集群里选出唯一 leader 并把一份日志按同一顺序复制给每个成员(可复制状态机)——拉票 `RAFT_VOTE_REQ`(0x70)/ 应答(0x71)、追加与心跳 `RAFT_APPEND`(0x72)/ 应答(0x73)、日志新旧约束选票、多数派提交本任期条目、提交点随 `commit` 字段带给跟随者、`next_index` 回退重试;崩溃容错、无堆无 libc、定长 RAM 日志(`ARK_BUS_RAFT_LOG_MAX`×`ARK_BUS_RAFT_ENTRY_MAX`),满则拒绝提案;关闭宏后零体积零符号(footprint 闸门 `[raft-on]` / 默认档 `[full]` absent)。见 [docs/consensus.md](docs/consensus.md) | | 集群运维/签名固件(`ARK_BUS_FWU_ENABLED`) | 完成;控制器对镜像算 `sha256` 再在摘要上做 `hmac_sha256` 签名,把 `{清单‖镜像}` 作为一个数据面对象流式下发,目标先本地重算摘要验签、通过才交给应用钩子(不写 flash);密钥不匹配/无密钥/超限一律拒绝不截断;对称签名(无 PKI),与整体信任模型一致。关闭宏后零体积零符号(footprint 闸门 `[fwu-on]` / 默认档 `[full]` absent)。见 [docs/fleet.md](docs/fleet.md) | | 载荷压缩(`ARK_BUS_COMPRESS_ENABLED`) | 完成;LZSS 压缩,压缩不划算时发送方清掉 `COMPRESSED` 标志(绝不放大);端到端往返有测,关闭宏后零体积零符号(footprint 闸门) | | 帧认证(`ARK_BUS_CRYPTO_ENABLED`) | 完成;预共享密钥下发送方对每帧加**截断 HMAC-SHA256 标签**(默认 8 字节,覆盖 14 字节头 `src\|dst\|msg_type\|flags\|topic_id\|payload_len` + payload,`seq` 默认不入签,开防重放后先占号再封签、`seq` 入签)、接收方**验签失败即丢弃**(含无标签帧,fail-closed),常时比较,失败计 `rx_auth_fail`;无密钥时行为零变化;关闭宏后零体积零符号(footprint 闸门 `[crypto-on]`)。见 [docs/authentication.md](docs/authentication.md) | | 载荷加密(`ARK_BUS_ENCRYPT_ENABLED`) | 完成;密钥派生 `mac_key`/`enc_key` 后以 **ChaCha20**(RFC 8439)加密载荷、对密文算标签(encrypt-then-MAC),nonce = `src_id`‖发送方 64 位计数器,线格式 `nonce(8)‖密文‖标签`;需 `ARK_BUS_CRYPTO_ENABLED`;关闭宏后零体积零符号(footprint 闸门 `[enc-on]`)。见 [docs/authentication.md](docs/authentication.md) | | 防重放窗口(`ARK_BUS_REPLAY_ENABLED`) | 完成;每对端 64 位滑动位图、`seq` 入签,只对有密钥、已验签、非 QoS1 帧生效;表满 fail-closed,重放计 `rx_replay`。见 [docs/authentication.md](docs/authentication.md) | | 握手与会话密钥(`ARK_BUS_HANDSHAKE_ENABLED`) | 完成;预共享密钥认证的**临时 X25519 ECDH** + HKDF-SHA256 派生**每对端会话密钥**,给出 pairwise 密钥、**密钥轮换**与**前向保密**(临时私钥用完即擦);握手帧用组密钥封以便随时重握手,线格式 52 字节(`ver‖role‖epoch‖eph_pk(32)‖tag(16)`),密钥选择三段回退(会话 cur → prev → 组密钥);`ark_bus_session_revoke` 置 `HS_REVOKED` 拒该对端非握手帧(`rx_denied`,检查在 crypto open 之前),`ark_bus_session_forget` 回落组密钥;**无强随机源默认拒握手**(`E_NOSYS`,仅 `ARK_BUS_CRYPTO_ALLOW_WEAK_RNG=1` 调试降级);信任锚仍是 PSK(无 PKI)。关闭宏后零体积零符号(footprint 闸门 `[hs-on]` / 默认档 `[full]` absent)。见 [docs/authentication.md](docs/authentication.md) | | 边缘分词(`ARK_BUS_TOKENIZER_ENABLED`) | 完成;贪心最长匹配的 encode / decode,词表由调用方静态提供,无堆无 libc;未知走逐字节 unk 兜底,`E_FULL` 不写并回填所需数量;关闭宏后零体积零符号(footprint 闸门 `[tok-on]`)。见 [docs/inference.md](docs/inference.md) | | Linux HAL | 完成,示例端到端运行通过 | | Ark RTOS 端口 | 骨架就位,编译检查通过;真机验证随 Ark RTOS 进行 | | 裸机端口 | 完成,宿主编译检查通过(ARM 下走 PRIMASK);真机验证待接入 MCU | | 算力损失基准 | 完成,宿主实测出数(见上);目标板周期数待重跑 | QoS1、发现、心跳、UART 逐字节解析、RPC 寻址、任务重派都在主机上验过;**真机多节点组网尚未验**—— 那需要两块板子接上同一根总线。M2 数据面已做分块传输与集合通信,控制面已知的边界 (无按任务 deadline、取消不打断 worker 等)逐条写在 [docs/control-plane.md](docs/control-plane.md), 数据面与集合通信的边界写在 [docs/data-plane.md](docs/data-plane.md)、[docs/collectives.md](docs/collectives.md), 推理适配层的契约与局限写在 [docs/inference.md](docs/inference.md), 可靠性层的契约(动态成员、流控、检查点的能/不能)写在 [docs/reliability.md](docs/reliability.md)。 ## 许可证 MIT,见 `LICENSE`。