Matter (connectedhomeip) 持久化键值存储 KVS API:persistent-storage 示例的构建、运行与平台实现差异
【免费下载链接】connectedhomeipMatter (formerly Project CHIP) creates more connections between more objects, simplifying development for manufacturers and increasing compatibility for consumers, guided by the Connectivity Standards Alliance.项目地址: https://gitcode.com/GitHub_Trending/co/connectedhomeip
本文以 Matter(Project CHIP)仓库中的persistent-storage示例为主线,讲解芯片平台层键值存储(Key-Value Storage,KVS)API 的设计与用法:如何构建并在 Linux / ESP32 / Qorvo QPG6200 平台上运行该示例、KeyValueStoreManager公开接口(Put/Get/Delete及其模板重载、偏移读)的语义与错误码、内置的 8 项 KVS 测试覆盖哪些边界场景,以及各平台实现完整度的差异(例如 ESP32 尚不支持偏移与部分读取)。读完本文,你可以复制该示例到自己平台验证 KVS 的 bring-up 质量,并理解其背后的实现分发机制。
示例定位:既是示例,也是平台 bring-up 测试
仓库文档入口 docs/examples/persistent_storage.md 是一个 Sphinx toctree 页面,它把persistent-storage目录下所有平台的 README 与 APPLICATION 文档聚合为“Persistent storage”章节:
- Linux 平台 README
- ESP32 平台 README
- QPG6200 APPLICATION 文档
各平台 README 对示例的定位描述一致:该示例既用于测试各平台 KVS 实现与 API 的 bring-up 质量,也作为 KVS API 的用法示范。文档同时说明,未来当该平台单元测试可用后,示例可迁移为标准单元测试。
从源码结构看,这种“双用途”设计体现在目录组织上:examples/persistent-storage/顶层放一份跨平台共享的测试代码 KeyValueStorageTest.h 与 KeyValueStorageTest.cpp,各平台子目录(linux/、esp32/、qpg/)只放各自的 main 入口和构建配置,测试逻辑复用同一份实现,保证各平台测的是同一组边界条件。
KeyValueStoreManager 公开 API 语义
示例使用的公共接口声明在 KeyValueStoreManager.h,核心方法如下。
Get:整值读取与偏移读取
CHIP_ERROR Get(const char * key, void * buffer, size_t buffer_size, size_t * read_bytes_size = nullptr, size_t offset_bytes = 0);- 返回值写入
buffer,实际读取字节数写入read_bytes_size(可传nullptr表示不关心); - 支持
offset_bytes从值的中间位置开始读——这是 KVS 相比传统 NVS 的重要能力,用于值大于单次读取缓冲的场景; - 若
buffer装不下整个值,返回CHIP_ERROR_BUFFER_TOO_SMALL,并尽量写入可写入的字节数。
错误码集合(Get/Put/Delete共用同一错误语义域,定义见头文件注释):
| 错误码 | 含义 |
|---|---|
CHIP_NO_ERROR | 操作成功 |
CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND | 键不存在 |
CHIP_ERROR_INTEGRITY_CHECK_FAILED | 找到条目但数据校验(完整性检查)失败 |
CHIP_ERROR_BUFFER_TOO_SMALL | 缓冲区装不下整个值,但已写入尽可能多的字节 |
CHIP_ERROR_UNINITIALIZED | KVS 尚未初始化 |
CHIP_ERROR_INVALID_ARGUMENT | 键为空、键过长或值过大 |
CHIP_ERROR_PERSISTED_STORAGE_FAILED | 写入/擦除底层失败(Put/Delete专用) |
模板重载:按类型推断大小
Put/Get各有一个模板重载(Put(key, const T&)/Get(key, T*)),对象大小由类型自动推断,源码里用static_assert强制约束类型合法性:
template <typename T> CHIP_ERROR Get(const char * key, T * value) { static_assert(std::is_trivially_copyable<T>(), "KVS values must copyable"); static_assert(!std::is_pointer<T>(), "KVS values cannot be pointers"); static_assert(CHAR_BIT == 8, "Current implementation assumes 8 bit."); return Get(key, value, sizeof(T)); }即值必须是可平凡拷贝(trivially copyable)且非指针的对象——这是把任意 C 结构体直接存进 KVS 的前提约束,示例中的TestStruct正是按此约束设计的。
平台分发机制
公共接口不直接实现存储逻辑。头文件末尾的 inline 函数把调用转发给平台实现类:
inline CHIP_ERROR KeyValueStoreManager::Get(const char * key, void * buffer, size_t buffer_size, size_t * read_bytes_size, size_t offset_bytes) { return static_cast<ImplClass *>(this)->_Get(key, buffer, buffer_size, read_bytes_size, offset_bytes); }并在文件尾部按编译期宏选择平台实现头:EXTERNAL_KEYVALUESTOREMANAGERIMPL_HEADER(外部注入)优先,否则由CHIP_DEVICE_LAYER_TARGET拼出<platform/<目标平台>/KeyValueStoreManagerImpl.h>。应用侧通过KeyValueStoreMgr()获取公共接口单例,通过KeyValueStoreMgrImpl()获取平台特化实现(如 Linux 下需要传初始化文件路径时的Init方法就是 impl 层接口)。
内置测试:8 项 KVS 边界条件
KeyValueStorageTest.cpp 中的RunKvsTest()依次运行 8 项测试,每项独立执行Put→Get→ 校验 →Delete,结果通过RUN_TEST宏打印PASSED/FAILED [错误信息]:
| 测试函数 | 覆盖场景 |
|---|---|
TestEmptyString | 存空字符串(长度为 0 的值的边界) |
TestKeyExistence | 以空缓冲(nullptr, 0)探测键存在性,允许返回成功或CHIP_ERROR_BUFFER_TOO_SMALL |
TestString | 普通字符串存取与strcmp一致性校验 |
TestUint32 | 单值整数存取 |
TestArray | 5 元素uint32_t数组存取与memcmp校验 |
TestStruct | 混合对齐结构体{uint8_t value1; uint32_t value2;}存取 |
TestUpdateValue | 同一键连续覆盖写 10 次并逐次读回,验证更新语义 |
TestMultiRead | 偏移读:对 5 元素数组从i*sizeof(uint32_t)处读 4 字节,前 4 次期望CHIP_ERROR_BUFFER_TOO_SMALL、最后一次期望CHIP_NO_ERROR |
TestMultiRead的期望行为值得注意——它直接验证了 KVS 头文件承诺的“缓冲不足时仍尽量写入并返回BUFFER_TOO_SMALL”语义。测试入口带配置开关(见 KeyValueStorageTest.h):
enum TestConfigurations { RUN_ALL_TESTS, SKIP_MULTI_READ_TEST }; void RunKvsTest(TestConfigurations test_config = RUN_ALL_TESTS);SKIP_MULTI_READ_TEST正是为尚不支持偏移/部分读取的平台准备的:这些平台调用RunKvsTest(SKIP_MULTI_READ_TEST)即可跳过TestMultiRead,其余 7 项照常运行。
Linux 平台:构建与运行
Linux 的 KVS 是全实现版本,初始化方式是在 init 调用中提供一个文件路径。linux/main.cpp 中的关键代码:
err = chip::Platform::MemoryInit(); SuccessOrExit(err); chip::DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().Init("/tmp/chip_example_kvs"); while (true) { printf("Running Tests:\n"); chip::RunKvsTest(); sleep(60); // Run every minute }即 Linux 平台 KVS 落盘在/tmp/chip_example_kvs文件中,测试循环每分钟跑一轮。完整构建与运行步骤(来自 linux/README.md):
# 安装工具链 $ sudo apt-get install git gcc g++ python pkg-config libssl-dev libdbus-1-dev libglib2.0-dev ninja-build python3-venv python3-dev unzip # 构建示例 $ cd ~/connectedhomeip/examples/persistent-storage/linux $ git submodule update --init $ source third_party/connectedhomeip/scripts/activate.sh $ gn gen out/debug $ ninja -C out/debug # 运行(需要写 /tmp,故用 sudo 运行) $ cd ~/connectedhomeip/examples/persistent-storage/linux $ sudo out/debug/persistent_storage注意仓库内该示例同时提供 GN 构建文件(BUILD.gn/args.gni),gn gen+ninja即为其标准构建路径。
QPG6200 平台:FreeRTOS 任务内的测试循环与日志输出
Qorvo QPG6200 的实现放在 FreeRTOS 静态任务中(见 qpg/main.cpp):Application_Init通过qvCHIP_init回调注册,创建一个 3KB 栈的静态任务,任务内循环打印Running Tests:、调用chip::RunKvsTest()后vTaskDelay(60000)每分钟一轮,与 Linux 的sleep(60)语义对齐。
APPLICATION.md 给出了预期的串口日志样例:
qvCHIP v0.0.0.0 (CL:170621) r:3 ============================ Qorvo KVS-Test Launching ============================ Starting FreeRTOS scheduler Consistency fail - tag:20ef Consistency failed Running Tests: [P][-] TestEmptyString(): PASSED [P][-] TestString(): PASSED [P][-] TestUint32(): PASSED [P][-] TestArray(): PASSED [P][-] TestStruct(): PASSED [P][-] TestUpdateValue(): PASSED [P][-] TestMultiRead(): PASSED这段日志有两点信息量:其一,QPG6200 上TestMultiRead通过,说明其 KVS 支持偏移读;其二,启动时打印的Consistency fail - tag:20ef/Consistency failed是 Qorvo 侧存储一致性检查的输出(对应 API 错误码语义中的完整性检查项),属于该平台存储驱动自检日志,而非测试失败。该文档还说明此应用不使用按钮、无 LED 输出,纯测试用途。
ESP32 平台:实现完整度限制
esp32/README.md 明确标注了实现限制:“The ESP32 platform KVS is not yet fully implemented. In particular offset and partial reads are not yet supported.”——即ESP32 平台 KVS 尚未完全实现,尤其不支持偏移与部分读取。这解释了为什么TestConfigurations中要专门提供SKIP_MULTI_READ_TEST开关:ESP32 上应跳过TestMultiRead,其余 7 项测试用于验证基本存取、更新与完整性路径。构建 ESP32 版本前需先按仓库文档配置 ESP-IDF 与 CHIP 环境(ESP-IDF 环境搭建、构建与配网指南)。
小结:如何把 KVS 验证移植到自己平台
从源码结构看,persistent-storage示例给出的平台接入范式是:
- 实现
<platform/<你的平台>/KeyValueStoreManagerImpl.h>,继承KeyValueStoreManager并提供_Get/_Put/_Delete,即可被公共头文件通过CHIP_DEVICE_LAYER_TARGET宏自动分发选中; - 链接共享的
KeyValueStorageTest.cpp/.h,在平台 main(裸机则放入 FreeRTOS 任务,POSIX 可直接循环)中调用chip::RunKvsTest(),不支持偏移读的平台传SKIP_MULTI_READ_TEST; - 以“全项 PASSED”作为该平台 KVS bring-up 完成的验收标准。
这样,一个不足百行的测试套件就完成了从空字符串、覆盖写到偏移读的全边界覆盖,而 API 层的类型约束(trivially copyable 非指针值)、错误码语义与实现分发机制,则保证了各平台 KVS 行为在KeyValueStoreMgr()这一统一入口下的一致性。
【免费下载链接】connectedhomeipMatter (formerly Project CHIP) creates more connections between more objects, simplifying development for manufacturers and increasing compatibility for consumers, guided by the Connectivity Standards Alliance.项目地址: https://gitcode.com/GitHub_Trending/co/connectedhomeip
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考