🏠 home › concepts › embedded-firmware-layering
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

相关概念