iotc 移植适配
·
iotc 移植适配指南
本文说明把 iotc(iot_connect)SDK 适配到新芯片/新平台时需要完成的工作、接口清单与注意事项。
一、总体思路
iotc 是分层结构:
应用层(业务回调、设备/服务信息)
│ IotcOhSetOption / IotcOhDevInit / IotcOhBleEnable / IotcOhMain
SDK 层 iotc/sdk/oh_connect/*
│
核心层 iotc/core/*(BLE 会话、SPEKE 安全、GATT 服务、上报、调度)
│ 只依赖适配层抽象接口
适配层 iotc/adapter/* ← 移植工作主要在这里
│
芯片平台(协议栈 / OS / 存储 / 加密 / TRNG / WiFi / SLE)
核心层不直接调用芯片 API,平台差异全部由适配层头文件(iotc_os.h、iotc_ble.h 等)隔离。
移植 = 选择裁剪范围 + 实现这些接口 + 把组件接入构建与启动流程。
二、第一步:确定裁剪范围
编译面由两部分共同决定:
- 构建系统的源码列表:决定哪些文件参与编译。未加入构建的目录,宏取任何值都不参与编译。
- 配置宏:决定已编文件内部的条件编译分支。
配置宏按来源分两类,不要混淆:
| 类别 | 来源 | 特点 |
|---|---|---|
| SDK 默认宏 | iotc_conf.h 中的 #ifndef 默认值 | 仅覆盖部分配置,可被编译选项覆盖 |
| 构建开关宏 | 只由构建选项提供,iotc_conf.h 中无默认值 | 不显式定义就完全不生效 |
常见宏:
| 宏 | 作用 | 默认值来源 |
|---|---|---|
| IOTC_CONF_BLE_ONLY | 只保留 BLE 通路,不编 WiFi/SLE/CoAP/TCP | 构建选项 |
| IOTC_CONF_BLE_SUPPORT | 启用 BLE | 构建选项 |
| IOTC_CONF_LITEOS_M_SUPPORT | LiteOS-M / 裸跑形态适配 | 构建选项 |
| IOTC_CONF_OH_NEARLINK_SUPPORT | 广播是否携带靠近发现扩展字段 | 构建选项 |
| IOTC_CONF_DEVICE_LEVEL | 设备等级,决定任务栈与缓冲区大小 | iotc_conf.h |
| IOTC_CONF_LOG_BUILD_LEVEL | 编译期日志级别 | iotc_conf.h |
| IOTC_CONF_TCP_SUPPORT | 是否启用 TCP | iotc_conf.h |
| IOTC_CONF_AES_SUPPORT | 是否启用 AES | iotc_conf.h |
| IOTC_CONF_ADAPTER_MBEDTLS_MAJOR_VERSION | mbedtls 主版本(2/3) | iotc_conf.h |
| IOTC_CONF_ADAPTER_SOCKET_LWIP_SUPPORT | socket 是否基于 lwIP | iotc_conf.h |
2.1 按宏的消费方式决定如何定义
- #if IOTC_CONF_XXX:按数值判断,-DIOTC_CONF_XXX=0 可关闭。
- #ifdef IOTC_CONF_XXX 或 #if defined(IOTC_CONF_XXX):只判断是否定义,
-DXXX=0 仍算已定义、仍生效;对无默认值的构建开关宏,只能不定义或用 -U。 - 例:IOTC_CONF_BLE_ONLY 以 #ifndef 判断,定义成任何值都表示“BLE-only 生效”。
- 例:IOTC_CONF_BLE_SUPPORT 若与 IOTC_CONF_WIFI_SUPPORT 用 defined() 组合判断,
写成 =0 会误开本应关闭的分支。
2.2 定义位置与默认值
- 只影响库内部实现的宏放 PRIVATE_DEFINES。
- 会影响公开头文件(被使用方 include)的宏必须放 PUBLIC_DEFINES,
否则库和使用方编译单元看到的值不一致。 - 所有功能开关应显式定义,不要依赖默认值;默认值可能为 1 或与平台不符。
- 不建议修改 SDK 头文件默认值:SDK 升级时会丢失,且不利于追踪差异。
裁剪原则:
- 先定源码列表,再定宏;未使用的适配目录保留但不加入构建即可。
- BLE-only 最小集合通常为:OS、BLE、Crypto、JSON、Log、Memory,以及核心 BLE/SPEKE/netcfg。
- WiFi/SLE/Socket/TLS 仅在确有联网或相应通路需求时编入。
- 注意第三方库版本差异带来的 API 变化,按实际版本增删适配代码。
三、适配层接口清单
以适配层头文件为准,接口数量可能随 SDK 版本变化。
| 模块 | 头文件 | 必需性 | 说明 |
|---|---|---|---|
| OS | iotc_os.h | 必须 | 任务、互斥、信号量、延时、时间、errno |
| BLE | iotc_ble.h | 必须(BLE 方案) | 广播、GATT Server、indicate/response、MAC |
| BLE HAL | ohos_bt_gatt*.h | 二选一 | 协议栈已有 OHOS HAL 时实现垫层 |
| 内存 | iotc_mem.h | 必须 | malloc/calloc/free |
| 日志 | iotc_log.h | 必须 | 日志输出与级别控制 |
| JSON | iotc_json.h | 必须 | JSON 解析/构造/打印 |
| 加密 | iotc_aes.h、iotc_md.h、iotc_kdf.h、iotc_drbg.h、iotc_mpi.h、iotc_rsa.h、iotc_base64.h | 必须 | 通常基于 mbedtls 适配 |
| KV | iotc_kv.h | 视需求 | 持久化密钥/会话/注册信息 |
| WiFi | iotc_wifi.h、iotc_network.h | 可选 | WiFi 配网/网络状态 |
| SLE | iotc_sle*.h | 可选 | SLE 通路 |
| Socket | iotc_socket.h | 可选 | TCP/UDP 通信 |
| TLS | iotc_tls.h | 可选 | 云连接加密 |
3.1 OS 适配(iotc_os.h)
主要接口:
任务:IotcTaskCreate / Suspend / Resume / Delete / GetCurrentTaskId
互斥:IotcMutexCreate / Lock / Unlock / Destroy
信号量:IotcSemCreate / Wait / Post / GetCount / Destroy
其它:IotcSleepMs / IotcSchedYield / IotcGetSysTimeMs / IotcGetErrno
注意点:
- 任务栈大小:默认值在低设备等级下偏小,BLE 会话 + mbedtls 场景需实测,
必要时调大默认栈或提高设备等级。 - 优先级映射:低/中/高优先级需映射到目标 OS 的合法区间。
- 时间单位:接口超时参数为毫秒,注意与 OS tick 换算。
- IotcTaskGetCurrentTaskId:需能反查到当前任务上下文。
- 互斥锁语义:确认目标 OS 是否支持递归锁、超时锁,iotc 内部存在嵌套加锁场景。
- IotcGetErrno:无 errno 的裸机环境可返回 0 或最近一次错误码。
3.2 BLE 适配(iotc_ble.h)
主要接口:
IotcBleInitStack / DeInitStack
IotcBleSetConnectParam / SetBleName
IotcBleStartAdv / StopAdv
IotcBleRegisterGattCb
IotcBleStartGattsService / StopGattsService
IotcBleSendGattsIndicate / SendGattsResponse
IotcBleGetBleMac / DisconnectGatt
两种实现路线:
路线 A:协议栈已提供 OHOS 风格 HAL(推荐)
只需实现一层 HAL 垫层,BLE 适配层可直接复用,改动量最小。
- 头文件:ohos_bt_gatt.h、ohos_bt_gatt_server.h、ohos_bt_def.h
- 实现内容:协议栈初始化/使能、广播参数与数据、MAC 读取、安全参数、
GATT server 注册/加服务/加特征/加描述符/启停服务/发送 indication 与 response - 关键接口示例:InitBtStack、EnableBtStack、SetDeviceName、BleSetAdvData、
BleStartAdv、BleStopAdv、BleUpdateAdv、ReadBtMacAddr、
BleGattRegisterCallbacks、BleGattsRegister、BleGattsAddService、
BleGattsAddCharacteristic、BleGattsStartService、BleGattsSendIndication
路线 B:协议栈没有 OHOS HAL
直接按 iotc_ble.h 实现全套接口,封装芯片原生 BLE 协议栈。
BLE 适配常见问题:
- UUID 字节序:适配层通常包含十六进制字符串与字节序转换,移植时不要改动其约定。
- 广播参数单位:interval 一般以 0.625ms 为单位,不是毫秒。
- 断开后不要重复开广播:iotc 内部已负责重连/重启广播,在断开回调中再次调用
启动广播接口会与内部逻辑重复,并可能因同步等待死锁。 - 回调上下文:协议栈回调多运行在协议栈线程或中断上下文,禁止阻塞、长打印、
直接调用同步 API,应投递到 iotc 调度器处理。 - GATT 句柄生命周期:删除/清理服务时要同步清理本地上下文,避免重连后句柄错乱。
- 连接参数/MTU/indicate 分片/CCCD:需与 iotc 的 profile 实现对齐。
- 全局符号冲突:HAL 中的全局变量可能与已有 BLE 库同名,注意编译选项或命名隔离。
3.3 熵源 / TRNG(必须)
- iotc 的 DRBG 初始化时会注册 TRNG 回调,用于 mbedtls 熵源。
- 应用侧通过设备选项注册 TRNG 回调。
- 无 /dev/urandom 的裸机环境必须接硬件 TRNG,否则熵源不可用或安全强度不足。
3.4 KV(视需求)
主要接口:
IotcKvInit / DeInit / SetValue / GetValue / GetLen / DelValue
- 用于持久化设备密钥、会话密钥、注册信息。
- 若要求重启后免重新配网/免重新注册,必须实现且保证掉电可靠:
建议写后校验、双备份、版本号管理。 - 需评估 NV/Flash 容量,预留密钥与会话数据空间。
3.5 其它适配
- 内存:保证 IotcMalloc/IotcCalloc/IotcFree 与 iotc 内部、JSON 释放策略一致;
IOTC_CONF_JSON_FREE_EQUAL_MALLOC_FREE 与实际释放方式匹配。 - 日志:中断上下文不要使用阻塞式打印。
- JSON:一般直接复用 cJSON,只需适配接口映射。
- Crypto:通常直接复用 mbedtls,重点处理版本宏与模块裁剪。
- Socket/TLS:仅在联网场景需要;TLS 还需要时间源与随机源回调。
- 网络状态:需映射到目标平台真实网络状态。
四、组件与构建集成
通用步骤:
- 顶层构建:把 iotc 组件(以及 BLE HAL 垫层,如有)加入顶层构建系统。
- 组件列表:把 iotc 组件加入目标的 RAM/镜像组件清单。
- iotc 组件构建:配置源码列表、include 路径、平台宏、依赖库与链接方式。
- 宏按可见性分 PRIVATE_DEFINES / PUBLIC_DEFINES:影响公开头文件的必须放 PUBLIC。
- 显式定义所有功能开关;#ifdef/defined() 类宏不能靠 =0 关闭。
- BLE HAL 组件构建:独立成组件,定义适配层识别宏,统一头文件与编译选项。
- 应用/示例:增加 sample 配置开关(Kconfig 等),并在目标配置文件中默认打开。
- 启动入口:使用平台支持的启动机制注册入口,确保在 OSAL/协议栈初始化之后执行。
链接注意:
- 入口函数常放在特殊初始化段中,需用 whole-archive/whole-link 方式链接,
否则会被当作死代码裁剪。 - 编译标准、告警选项、C 运行时配置按平台约定设置。
- 依赖库:OSAL、BLE 协议栈、安全库/安全 C 库(securec 等)头文件路径。
五、与既有 BLE 业务共存
同一芯片上不能同时运行两套 GATT Server / 广播:
- 关闭基线 BLE 的初始化入口,避免两套代码都注册 GATT 回调或启动广播。
- 广播句柄、GATT serverId、回调注册保持全局唯一。
- 若平台还使用 SLE 等其它无线通路,确认其初始化顺序与共享资源不冲突。
- BLE 使能回调必须注册并返回成功,否则 BLE 使能流程会报错(部分错误非致命,但应消除)。
六、分区与资源规划
- iotc + mbedtls 会显著增大应用镜像,需要重新规划 Flash 分区:
- 应用分区大小
- FOTA 区偏移/大小
- NV/KV 区大小与对齐
- 修改分区配置后必须重新生成分区表镜像,并同步所有 target 的配置。
- 资源评估:
- Flash:应用镜像、KV/NV、FOTA 预留
- RAM:iotc 任务栈、mbedtls 上下文、JSON 缓冲、协议栈缓冲
- 内核对象:任务数、信号量数、互斥锁数上限是否足够
七、同平台换芯片型号的额外检查
- 预编译库符号差异:用 nm/readelf 比对基线库,确认 iotc 依赖的符号存在;
缺失时通过条件编译隔离或改用替代接口。 - 分区布局:不同型号 Flash 大小不同,APP/FOTA/NV 偏移必须分别核算。
- 配置项:每个 target 的配置文件都要更新,不能只改一个默认配置。
- 协议栈能力:确认广播扩展、indication、MTU、连接数等能力一致。
- 时钟/低功耗:确认休眠唤醒后的 BLE 保连、时钟漂移校准等接口是否存在。
八、安全参数一致性
- pincode:iotc 按固定长度参与 HKDF,必须填满定义长度且与 App 侧逐字节一致,
否则 SPEKE 共享密钥不同、HMAC 校验失败。 - acKey:长度与内容需与云端/App 登记值一致。
- 设备信息:产品 ID、设备类型 ID、型号、厂商 ID 等必须与云端产品定义一致。
- 时间源:TLS/证书校验依赖时间,启用时需提供获取时间回调。
- 密钥存储:KV 实现需防掉电损坏,建议双备份 + 校验。
九、移植步骤(建议顺序)
- 选定裁剪范围,配置 IOTC_CONF_* 宏。
- 实现 OS 适配,单独验证任务/互斥/信号量/延时。
- 实现内存、日志、JSON,跑通 iotc 核心初始化。
- 接入 TRNG 回调,确认 DRBG 初始化成功。
- 实现 BLE(优先走 HAL 垫层 + 现有适配层)。
- 实现 KV(若需要持久化)。
- 接入构建:顶层构建、组件列表、sample 开关、目标配置。
- 处理与基线 BLE/外设的共存,注册启动入口。
- 调整分区并重新生成分区表。
- 按验证清单逐项验收。
十、验证清单
| 阶段 | 验证项 | 期望 |
|---|---|---|
| OS | 任务创建/删除、互斥/信号量超时 | 无死锁、无栈溢出 |
| 核心 | 设备初始化、主循环启动 | 接口返回成功,任务正常运行 |
| 熵源 | DRBG 初始化 | 无初始化失败日志 |
| BLE | 手机扫描设备 | 广播名与厂商字段正确 |
| 会话 | SPEKE 协商与鉴权 | 配对成功,无 HMAC 失败 |
| 业务 | 属性读写、全量上报 | 读写与上报均成功 |
| 存储 | 掉电重启 | 密钥/注册信息保持 |
| 稳定性 | 断连重连、长时间运行 | 广播恢复、无句柄泄漏、无死锁 |
| 低功耗 | 休眠唤醒 | 保连正常、广播可恢复 |
十一、常见问题检查表
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 初始化失败 | 熵源未接入/TRNG 返回失败 | 检查 TRNG 回调与 DRBG 日志 |
| 扫描不到设备 | 广播参数单位错误、广播未启动 | 核对 interval 单位与启动返回值 |
| 配对失败/HMAC 失败 | pincode 长度或内容不一致 | 核对固定长度与 App 配置 |
| 断连后死锁 | 断开回调中重复启动广播/调用同步 API | 移除重复启动,改为异步投递 |
| 重连后读写异常 | GATT 句柄/上下文未清理 | 检查服务删除与上下文生命周期 |
| 链接失败 | 预编译库缺符号、初始化段被裁剪 | nm 比对符号,检查 whole-link |
| 栈溢出/重启 | 任务栈不足、中断中阻塞 | 增大栈、检查回调执行上下文 |
| 掉电后需重新配网 | KV 未实现或写入不完整 | 检查 KV 掉电可靠性与容量 |
| 镜像放不下 | 分区未重新规划 | 调整 APP/FOTA/NV 分区并重生成分区表 |
| 宏设了不生效/关不掉 | 宏用 #ifdef/defined() 消费,=0 仍算定义 | 改为不定义或 -U,并确认 PRIVATE/PUBLIC 可见性 |
更多推荐
所有评论(0)