- tags
- [IoT, 嵌入式, 架构, 分层, Hexagonal, BK7258]
- created
- 2026-04-24
- updated
- 2026-04-24
- sources
- [raw/snippets/bk7258-build/iot-architecture-onboarding.md]
定义¶
Sentino BK7258 AI 玩具固件采用四层架构:业务层(projects/{产品}/main)/ 适配层(rino_interface)/ SDK 层(rino_iot_sdk)/ BSP 层(platform_adapter)。这套分层等价于后台世界的 Hexagonal / Ports & Adapters 架构在嵌入式的体现,目标是99% 的产品迭代只动业务层——SDK 不知道设备是玩具还是灯,BSP 不知道业务长什么样,换芯片只换 BSP 一层。
四层职责¶
┌───────────────────────────────────────────────────┐
│ 业务代码 projects/{产品名}/main/ │ 每个产品都不同
│ rino_iot_process.c ← DP 点业务、设备状态 │
│ app_agora_session_process.c ← AI 对话 │
│ app_main.c, key_app_*.c, app_led.c, bat_monitor.c │
└───────────────────────────────────────────────────┘
↕ import callbacks / export APIs
┌───────────────────────────────────────────────────┐
│ 适配层 projects/common_components/rino_interface/ │ 每个项目少量调整
│ ★ "接线盒",无业务逻辑,纯转发 │
│ rino_system_import_interface.c 灌系统调用 │
│ rino_periph_import_interface.c 灌外设 │
│ rino_mqtt_import_interface.c 灌 MQTT 业务 cb │
│ rino_mqtt_export_interface.c 透出业务 API │
└───────────────────────────────────────────────────┘
↕ 函数指针
┌───────────────────────────────────────────────────┐
│ SDK projects/common_components/rino_iot_sdk/ │ 极少改(升级协议时)
│ 通用,跨项目复用,不依赖具体硬件和业务 │
│ rino_app/ 业务编排、消息队列、配网状态机 │
│ rino_mqtt/ MQTT 协议封装 │
│ rino_ble/ 蓝牙配网 │
│ rino_wifi/ WiFi STA/scan │
│ rino_http_ota/ OTA 升级 │
│ rino_protocol/ 授权 + TLS │
│ factory_test/ 厂测动态注册 │
└───────────────────────────────────────────────────┘
↕
┌───────────────────────────────────────────────────┐
│ BSP projects/common_components/platform_adapter/ │ 换芯片时整层换
│ 板级支持包,封装 ARMINO SDK + FreeRTOS + BK7258 │
│ Bsp_Wifi_*, Bsp_Ble_*, Bsp_Flash_*, Bsp_Mem_* │
└───────────────────────────────────────────────────┘
import vs export 命名约定(反向依赖视角)¶
适配层的命名是从 SDK 的视角看的:
| 命名 | 方向 | 角色 | 类比后台 |
|---|---|---|---|
| import | 外 → SDK 内 | SDK 调用上层提供的函数(回调注入) | Spring DI 把 Bean 注入到 SDK |
| export | SDK 内 → 外 | 上层业务调用 SDK 暴露的函数(API 透出) | SDK 暴露的接口包 |
→ 等价于 Hexagonal / Ports & Adapters 在嵌入式里的体现:SDK 是六边形内核,import 接口是 Driven Port(被动暴露给业务回填),export 接口是 Driving Port(主动暴露给业务调用)。
各层职责对照表¶
| 层 | 知道什么 | 不知道什么 | 谁会换 |
|---|---|---|---|
projects/{产品}/main/ |
"我是 AI 玩具,dpid=3 是音量" | MQTT 协议长什么样 | 每个产品都不同 |
rino_interface/ |
"SDK 有哪些 hook、业务有哪些函数" | 业务的具体含义、协议细节 | 每个项目少量调整 |
rino_iot_sdk/ |
"MQTT 怎么连/订阅/JSON 怎么解" | 设备是玩具还是灯、芯片是哪家 | 极少改(升级协议时) |
platform_adapter/ |
"BK7258 的 WiFi/BLE/Flash API" | 上面跑什么业务 | 换芯片时整层换 |
→ 跨界知识传递的方向:业务 → 适配("我新增一种 DP 点处理");适配 → SDK("这是处理函数指针,请调它");SDK → BSP("请调用底层 WiFi API 连接 SSID")。反向不允许:SDK 不能知道业务、BSP 不能知道 SDK 上层有什么。
三条业务链路示例(验证分层价值)¶
链路 ①:APP 改音量 → 喇叭变音量(云 → 设备)¶
APP 滑音量条
↓ HTTP
云平台
↓ MQTT publish: {"code":"property_set","value":{"volume_set":7}}
rino_iot_sdk/rino_mqtt/ ← SDK 层:解码 → 丢消息队列 → cmd_parse
↓ Cmd_Property_Set_Parse_Cb (注入的 callback)
rino_interface/rino_mqtt_import_interface.c:161 ← 适配层:纯转发
Rino_Mqtt_Cmd_Property_Set_Parse_Import_Callback(dp)
└─→ Dev_Dp_Obj_Callback(dp)
↓
projects/beken_genie/main/rino_iot_process.c:262 ← 业务层:知道 dpid=3 是音量
case DPID_VOLUME_SET:
Volume_Set_Abs(7, 0); ← 调音频驱动
DP_Volume_Set_Report(7); ← 反向上报
↓
rino_iot_sdk/ → MQTT publish: $thing/.../property_report
↓
云平台更新 shadow → APP 看到音量已变
→ SDK 完全不知道"音量"这件事,只知道收到了 property_set 命令并按 callback 链向上传。
链路 ②:开机自动上报状态(典型回调注入模式)¶
rino_iot_sdk/rino_mqtt/rino_mqtt_app.c:108
Rino_Mqtt_Connected_Callback() 触发
末尾调 Rino_Mqtt_App_Ready_Cb()
↓
rino_interface 启动时注入:
Register_Rino_Mqtt_App_Ready_Cb(Device_Power_On_Report_Info)
↓
projects/beken_genie/main/rino_iot_process.c:188
Device_Power_On_Report_Info() {
DP_Bright_Value_Report(...);
DP_Switch_Status_Report(...);
}
→ SDK 只暴露抽象 hook("我连上 MQTT 了,要不要做点什么?"),适配层接到具体业务函数。业务函数叫什么名字 SDK 不知——这是 import 命名的精髓。
链路 ③:长按按键 → AI 对话启动(设备 → 云)¶
按键事件
↓ 业务调 export 接口
rino_interface/rino_mqtt_export_interface.c:27
Rino_Device_Access_Export_Interface()
└─→ Mqtt_Event_Agora_Agent_Device_Access_Report(1)
↓
rino_iot_sdk/ 构造 event payload → MQTT publish
↓
云平台 → 调 AI Agent → 申请声网 RTC token → 应答
↓
MQTT 推回设备 → SDK 解析事件应答
↓
rino_interface/rino_mqtt_import_interface.c:95
Rino_Mqtt_Event_Respone_Agora_Agent_Device_Access_Parse_Import_Callback
├─ result==0 → set_agora_config(rtcToken, channelName, appId, uid)
└─ result!=0 → app_event_send_msg(APP_EVT_ASR_WAKEUP_FAIL, 0)
↓
app_agora_session_process.c
加入声网频道 → 开音视频对话
→ export 是业务主动调 SDK,import 是 SDK 反向回调业务——这条链路同时展示了两种方向。
"换需求改哪层"决策表¶
| 需求 | 改的位置 |
|---|---|
| 加 DP 点 | rino_iot_process.h 加 DPID + .c 加 case |
| 改 AI 对话触发条件 | app_agora_session_process.c |
| 改长按按键行为 | key_app_server.c + 调 export 接口 |
| 接入云端新增命令 | rino_mqtt_import_interface.c 加新 callback |
| 换连接的云平台域名 | rino_iot_sdk/rino_iot/rino_iot_common.h(注:当前 Sentino 走蓝牙配网下发,详见 iot-device-bootstrap) |
| 换芯片 | 整个 platform_adapter/ 重写 |
→ 99% 的产品迭代只动 projects/{产品}/main/,这就是这套架构的回报。
与 4G 设备形态的兼容性¶
切换到 4G 设备(详见 iot-device-bootstrap)时,按这套分层应该改:
| 改动 | 工作量 | 改在哪 |
|---|---|---|
重写 Bsp_Tcp_* 为 AT 指令驱动 |
中 | platform_adapter/bsp_network.c |
| 替换 WiFi callback 为 4G 状态查询 | 小 | rino_interface/rino_periph_import_interface.c |
| 跳过配网逻辑,开机直接进运行态 | 小 | rino_iot_sdk/rino_app/rino_os_system.c:32 |
| 增加 4G 状态机(模组上电 → SIM → 注网 → 拨号) | 中 | 新建 bsp_cellular.c |
| 接入 MQTT host/port(推荐方案 B 引导服务器) | 中 | 改 factory_dynamic_register.c 或新建 bootstrap 客户端 |
| MQTT keepalive 拉长到 300s(避免运营商 NAT 超时 + 省流量) | 极小 | rino_iot_sdk/rino_mqtt/rino_mqtt_app.c:216 Keepalive=60 |
rino_iot_sdk 上层、业务代码 |
零改动 | - |
→ SDK 看到的永远是 Tcp_Connect/Read/Write,底层走 WiFi 还是 4G 它不关心。这是分层架构在 SoC 切换、网络方式切换、产品形态切换三个维度的共同价值。
与 Harness Engineering 的连接¶
适配层(rino_interface)的角色与 harness-engineering 第三代 Agent 工程范式中"模型之外的一切"高度同构——都是在固定核心(这里是 SDK,那里是 LLM)周围搭出可替换的环境层。区别在于:嵌入式的"环境"是硬件 + 业务回调,Agent 的"环境"是工具 + memory + context。但"把核心做成黑盒、把环境做成可替换层"的原则一致。
→ Sentino 同时在嵌入式(rino_interface 适配层)和 Agent 平台(sentino-agent standalone agent + agent-tool-design)两个领域做这种分层,是组织级的架构判断一致性。
关键路径速查(业务接入用)¶
| 关注点 | 文件 |
|---|---|
| SDK 入口(开机分流) | rino_iot_sdk/rino_app/rino_os_system.c:24 |
| 全局事件总线 | rino_iot_sdk/rino_app/rino_msg_queue.c:91 |
| MQTT 任务循环 | rino_iot_sdk/rino_mqtt/rino_mqtt_app.c:198 |
| MQTT 鉴权签名 | rino_iot_sdk/rino_mqtt/rino_mqtt_app.c:35 |
| 系统调用注入 | rino_interface/rino_system_import_interface.c |
| 外设/Flash 注入 | rino_interface/rino_periph_import_interface.c |
| MQTT 业务 callback 注入 | rino_interface/rino_mqtt_import_interface.c |
| 业务对外 API | rino_interface/rino_mqtt_export_interface.c |
| 业务物模型定义 | projects/{产品}/main/rino_iot_process.h |
| AI 对话业务 | projects/{产品}/main/app_agora_session_process.c |
相关概念¶
- iot-platform-fundamentals — 后台 vs IoT 概念对照表(包含本页 import/export ↔ Spring DI 一行)
- iot-device-bootstrap — 4G 形态下 BSP 层重写 + 引导服务器接入路径
- bk7258-firmware — BSP 层封装的具体硬件 SDK 与编译烧录细节
- mqtt-device-protocol — SDK 层 MQTT 协议封装的对外语义
- ble-provisioning — SDK 层 rino_ble 模块的对外语义
- device-lifecycle — 业务层在生命周期不同阶段调 export 接口的入口表
- harness-engineering — 适配层 ↔ Harness 概念同构
- sentino-iot — 这套分层在 Sentino IoT 完整产品里的位置