Hi3516CV610 获取设备 Unique ID 实战

Hi3516CV610 获取设备 Unique ID 实战 仙女养的猪 2026-06-30 10:04:29 438

Hi3516CV610 获取设备 Unique ID 实战

背景说明

本文基于下面这套实际环境整理:

  • 芯片平台:Hi3516CV610
  • SDK 版本:Hi3516CV610_SDK_V1.0.2.1
  • 工程类型:MPP Sample 工程
  • 示例模块:daemon 目录下的测试程序
  • 验证方式:通过 make test 交叉编译、上传到板端并远程执行

如果你的环境与本文接近,尤其是同一大版本 SDK,那么接口名称、头文件位置和链接依赖通常都可以直接参考。

如果你使用的是其它芯片型号,或者是不同大版本的 SDK,那么也建议先按本文介绍的方法去定位头文件、结构体定义和链接库,而不是直接照抄代码。

做设备注册、设备绑定、云端鉴权这类功能时,第一步通常不是写网络请求,而是先回答一个更基础的问题:

这台设备,到底用什么来唯一标识?

在 Hi3516CV610 这类 SDK 项目里,很多人第一反应是去业务代码里找 uuidserialdevice_id,但实际排查后会发现,这类唯一标识往往不是业务层自己生成的,而是厂商 SDK 直接提供。

这篇文章就结合一次真实排查过程,讲清楚下面几件事:

  • 如何在 Hi3516CV610 SDK 中定位设备唯一标识接口
  • ss_mpi_sys_get_unique_id() 到底是什么
  • 为什么代码能编过、链接却失败
  • 如何把 unique id 真正跑通并打印出来

先说结论:
在这套 SDK 里,可以通过 ss_mpi_sys_get_unique_id() 获取设备唯一标识,但它返回的不是标准 RFC 4122 格式的 UUID 字符串,而是 SDK 定义的 ot_unique_id 数组。因此更准确的说法应当是 Unique ID,而不是严格意义上的 UUID

一、先别写代码,先定位接口

如果你接手的是一个现成工程,最稳妥的做法不是直接猜 API,而是先在 SDK 头文件里查“唯一标识”相关接口。

这次排查里,最终定位到的声明在:

声明如下:

td_s32 ss_mpi_sys_get_unique_id(ot_unique_id *unique_id);

看到这行之后,至少能确定三件事:

  • 这是系统级 MPI 接口,不是业务层自己封装的函数
  • 返回值是 td_s32,也就是标准 SDK 风格的状态码
  • 输出参数是 ot_unique_id *,说明结果不是直接返回字符串

继续往下查 ot_unique_id 的定义,可以在:

对应定义是:

typedef struct {
    td_u32 id[OT_UNIQUE_ID_NUM];
} ot_unique_id;

数组长度常量在:

定义为:

#define OT_UNIQUE_ID_NUM 6

这一步很重要,因为它直接决定了你后面的打印方式。

很多人这里会犯一个错误:
一看到 get_unique_id 就默认它返回的是标准 UUID 字符串,结果后面输出格式、存储格式、上传格式全都设计错了。

二、最小可运行代码怎么写

如果目标只是先把设备 unique id 跑出来,最小示例完全不需要混进复杂业务流程。

一个足够干净的写法如下:

#include <iostream>
#include "ss_mpi_sys.h"

int main()
{
    ot_unique_id unique_id = {};
    td_s32 ret = ss_mpi_sys_get_unique_id(&unique_id);
    if (ret != TD_SUCCESS) {
        std::cerr << "读取 unique id 失败: 0x" << std::hex << ret << std::dec << std::endl;
        return 1;
    }

    std::cout << "unique id:";
    for (td_u32 i = 0; i < OT_UNIQUE_ID_NUM; ++i) {
        std::cout << std::hex << unique_id.id[i];
    }
    std::cout << std::dec << std::endl;
    return 0;
}

这个版本里,有几个细节值得注意:

  • ot_unique_id unique_id = {}; 用来保证结构体先清零
  • 失败时把返回码按十六进制打印,方便和 SDK 错误码体系对照
  • unique_id.id[i] 是一个 td_u32 数组,所以最直接的打印方式就是循环输出十六进制值

如果你只是验证接口是否可用,这一版就够了。

三、为什么单文件编译通过,但 make 还是失败

这是这次踩坑里最典型的一步。

把上面的代码写进测试程序之后,单文件语法检查通常是能过的。因为这一步只验证两件事:

  • 头文件能不能找到
  • 类型和函数声明能不能识别

但真正执行 make test 时,问题会出在链接阶段:

undefined reference to `ss_mpi_sys_get_unique_id`

这类报错说明什么?
说明编译器已经相信“这个函数确实存在”,但链接器在最终拼二进制时,没找到真正实现它的静态库或动态库。

换句话说:
头文件找到了,库没链上。

四、实现不在源码里,而在厂商库里

继续往下排查,会发现项目源码里根本搜不到 ss_mpi_sys_get_unique_id 的函数体。

这并不奇怪,因为它属于厂商 SDK 提供的 MPI 接口,实现通常放在预编译库中。

实际排查后,可以确认这个符号来自:

这也是为什么很多人会误以为“工程里没有这个函数”,实际上不是没有,而是你只能看到声明,看不到实现。

五、真正的坑不止一个库

很多人修到这里,会直接在链接命令里补一个 libss_mpi.a,然后继续编译。

结果第二轮常见会遇到新的错误,比如:

  • memcpy_s 未定义
  • memset_s 未定义
  • strncpy_s 未定义
  • snprintf_s 未定义

这说明 libss_mpi.a 本身还依赖别的库。

在这套 SDK 里,最稳妥的做法不是只手工补一个 libss_mpi.a,而是直接复用 SDK 已经整理好的整组 MPI 依赖。

当前项目的依赖集合定义在:

测试目标最终采用的方式是:

  • 复用 $(MPI_LIBS)
  • 额外补 libsecurec.a

对应位置在:

这种写法的好处非常明确:

  • 你不用自己猜 libss_mpi.a 后面还依赖哪些 MPP 库
  • securec 的安全函数依赖也一并解决
  • 测试目标和 SDK 原本的构建方式更一致,后续维护成本更低

六、项目里是怎么接进去的

当前示例程序放在:

这个测试程序现在做了两件事:

  • 读取并打印 unique id
  • 读取并打印 CPU 温度

其中 unique id 的关键逻辑就是:

ot_unique_id unique_id = {};
td_s32 ret = ss_mpi_sys_get_unique_id(&unique_id);
if (ret != TD_SUCCESS) {
    std::cerr << "读取 unique id 失败: 0x" << std::hex << ret << std::dec << std::endl;
    return 1;
}

std::cout << "unique id:";
for (td_u32 i = 0; i < OT_UNIQUE_ID_NUM; ++i) {
    std::cout << std::hex << unique_id.id[i];
}
std::cout << std::dec << std::endl;

这段逻辑没有做任何复杂封装,目的就是先把接口确认跑通。

七、如何验证真的成功了

在这个项目里,最直接的验证方式就是进入 daemon 目录执行:

make test

这个命令不是单纯本地编译,它会:

  • 编译测试程序
  • 链接生成测试二进制
  • 上传到板端
  • 远端执行测试程序

实际运行结果类似这样:

unique id: 37020a14-21c9071c-46e544d9-fa7ea8c0-3c701-7
当前 CPU 温度: 43 C

这里还要再提醒一次:
这个输出虽然看起来像某种分段 ID,但它不等同于标准 UUID 文本格式。它本质上仍然是厂商 SDK 返回的一组设备唯一标识数据。

八、如果你要把它用于设备注册

当你已经拿到 unique id 之后,后面的典型用途通常有三种:

  • 作为设备注册接口的唯一设备标识
  • 作为设备端启动日志的一部分,方便产测和售后定位
  • 和温度、版本号、网络信息一起组成设备自检输出

如果是上报到服务端,我建议额外做一步格式标准化,例如:

  • 每段统一按固定宽度十六进制输出
  • 增加分隔符
  • 明确大小写风格

这样服务端更容易做存储、检索和比对。

九、这类问题真正该学会的,不是 API 名字

很多人看完类似文章,最想记住的是:
“Hi3516CV610 获取唯一标识用 ss_mpi_sys_get_unique_id()。”

这当然没错,但更重要的其实是这套排查思路:

  1. 先在 SDK 头文件里定位声明
  2. 再查输出参数的数据结构
  3. 不要把 Unique ID 想当然当成标准 UUID
  4. 编译过了不代表结束,链接阶段才是真正的依赖检查
  5. 厂商 SDK 接口通常不在源码里,而在预编译库里
  6. 能复用 SDK 的库集合时,不要自己零散手补依赖

你真正掌握的是这套方法,下次碰到 chip idcustom codeserialotp 之类系统级接口时,排查效率会快很多。

十、总结

在 Hi3516CV610 这套 SDK 中,获取设备唯一标识的关键并不在“调用一个函数”本身,而在于把下面三件事做对:

  • 找到正确的系统接口 ss_mpi_sys_get_unique_id()
  • 理解返回值不是字符串,而是 ot_unique_id 数组
  • 在工程构建里把 MPI_LIBSlibsecurec.a 这类依赖链完整补齐

如果你现在只是想先验证设备是否能读出唯一标识,那最小测试程序已经足够。
如果你下一步要做设备注册、设备首次激活或者产测工具,把这个 unique id 做成统一格式再上报,会比直接裸打印更稳。

如果后续你还想继续展开,一个自然的下一篇可以是:
《Hi3516CV610 如何把 Unique ID 上报到设备注册接口》。

声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包 1 收藏 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
仙女养的猪
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区