从零开发Matter 新的设备类型产品

[English]

这一小节通过在bk_matter基础上,新建一个 On/Off Plug 的Matter应用,用于详细说明bk_matter创建Matter新设备类型的过程。

zap文件配置

zap文件是Matter的一个配置文件,可以通过参照 matter协议 Device Library Specification 对要实现的设备类型进行配置,关于zap工具的使用可以参考 Matter 配置工具 ZAP

关于Matter的一些基本概念的介绍可以参考 Matter 简介

zap工具会根据Matter的开发有多个版本,因此在目录 components/matter/connectedhomeip/zap 中包含了两个可执行文件:

  • zap: 用于对zap文件进行可视化的编辑。修改配置zap文件时需要用到这个工具。

  • zap-cli: 用于解析zap文件,在编译过程中会用到。

On/Off Plug设备将会包括两个endpoint。

endpoint 0 设备类型为 0x0016(Matter Root Node),包含了Matter所有基础的cluster,基础信息配置(Basic Information cluster)、wifi(Network Commissioning,WiFi Network Diagnostics)、OTA(OTA Software Update Provider,OTA Software Update Requestor)等,对于所有类型的设备,这部分基本都一样。因此比较方便的做法是,直接在 examples/lighting-app/lighting-common/lighting-app.zap 文件的基础上进行修改,只保留endpoint 0 即可,按需添加新的endpoint即可。

endpoint 1 设备类型为 0x010A(On/Off Plug-in Unit),对于具体cluster的配置,需要参考 Device Library Specification 文档。

On/Off Plug-in Unit Cluster Requirements

ID

Cluster

Client/Server

Quality

Conformance

0x0003

Identify

Server

M

0x0004

Groups

Server

M

0x0005

Scenes

Server

P,M

0x0006

On/Off

Server

M

0x0008

Level Control

Server

O

将文件保存为 on-off-plug.zap ,在下一小节中将会用到。

创建gn项目

  1. 首先创建一个文件夹 components/matter/connectedhomeip/examples/on-off-plug/beken ,用于存放新设备的代码和配置。

mkdir -p components/matter/connectedhomeip/examples/on-off-plug/beken
  1. 创建一些软链接,引入需要的一些依赖。

cd components/matter/connectedhomeip/examples/on-off-plug/beken
mkdir third_party
ln -s ../../build_overrides build_overrides
ln -s ../../../.. connectedhomeip
  1. 创建文件 .gn ,gn项目的配置文件

 1# Copyright (c) 2022 Project CHIP Authors
 2#
 3# Licensed under the Apache License, Version 2.0 (the "License");
 4# you may not use this file except in compliance with the License.
 5# You may obtain a copy of the License at
 6#
 7# http://www.apache.org/licenses/LICENSE-2.0
 8#
 9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import("//build_overrides/build.gni")
16import("//build_overrides/chip.gni")
17
18# The location of the build configuration file.
19buildconfig = "${build_root}/config/BUILDCONFIG.gn"
20
21# CHIP uses angle bracket includes.
22check_system_includes = true
23
24default_args = {
25  target_cpu = "risc-v"
26  target_os = "freertos"
27
28  import("//args.gni")
29}
  1. 创建文件 args.gn 对项目进行一些默认配置。

 1# Copyright (c) 2022 Project CHIP Authors
 2#
 3# Licensed under the Apache License, Version 2.0 (the "License");
 4# you may not use this file except in compliance with the License.
 5# You may obtain a copy of the License at
 6#
 7# http://www.apache.org/licenses/LICENSE-2.0
 8#
 9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15# Options from standalone-chip.mk that differ from configure defaults. These
16# options are used from examples/.
17
18import("//build_overrides/chip.gni")
19
20chip_device_platform = "beken"
21
22chip_project_config_include = ""
23chip_system_project_config_include = ""
24chip_ble_project_config_include = ""
25
26mbedtls_target = "${chip_root}/config/beken/mbedtls:mbedtls"
27lwip_platform = "external"
28
29chip_build_tests = false
30
31chip_inet_config_enable_tcp_endpoint = true
32chip_inet_config_enable_udp_endpoint = true
33
34chip_config_network_layer_ble = true
35chip_config_memory_management = "platform"
36chip_enable_additional_data_advertising = false
37chip_enable_rotating_device_id = true
38chip_enable_ota_requestor = false
39chip_inet_config_enable_ipv4 = true
40
41chip_detail_logging = false
42chip_automation_logging = false
43
44custom_toolchain = "${chip_root}/config/beken/toolchain:beken"

其中第20行通过 chip_device_platform = "beken" 制定了Matter的编译平台,编译时将会使用 src/platform/beken 下的源码。

  1. 创建 BUILD.gn 用于设置项目源码等。

 1# Copyright (c) 2020 Project CHIP Authors
 2#
 3# Licensed under the Apache License, Version 2.0 (the "License");
 4# you may not use this file except in compliance with the License.
 5# You may obtain a copy of the License at
 6#
 7# http://www.apache.org/licenses/LICENSE-2.0
 8#
 9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import("//build_overrides/build.gni")
16import("//build_overrides/chip.gni")
17import("${chip_root}/examples/common/pigweed/pigweed_rpcs.gni")
18import("${chip_root}/src/app/chip_data_model.gni")
19import("${chip_root}/examples/on-off-plug/beken/args.gni")
20
21examples_plat_dir = "${chip_root}/examples/platform/beken"
22
23chip_data_model("on-off-plug") {
24  zap_file = "on-off-plug.zap"
25
26  is_server = true
27}
28
29static_library("MatterApp") {
30  public_deps = [
31    ":on-off-plug",
32    "${chip_root}/examples/providers:device_info_provider",
33    "${chip_root}/src/platform/logging:default",
34  ]
35
36  include_dirs = [
37    "${chip_root}/examples/on-off-plug/beken/main/include",
38    "${examples_plat_dir}",
39  ]
40
41  if (chip_enable_ota_requestor) {
42    sources = [
43      "${examples_plat_dir}/common/BekenAppServer.cpp",
44      "${examples_plat_dir}/common/CHIPDeviceManager.cpp",
45      "${examples_plat_dir}/common/CommonDeviceCallbacks.cpp",
46      "${examples_plat_dir}/ota/OTAHelper.cpp",
47      "main/DeviceCallbacks.cpp",
48      "main/DsoHack.cpp",
49      "main/chipinterface.cpp",
50      "main/Plug.cpp",
51    ]
52  } else {
53    sources = [
54      "${examples_plat_dir}/common/BekenAppServer.cpp",
55      "${examples_plat_dir}/common/CHIPDeviceManager.cpp",
56      "${examples_plat_dir}/common/CommonDeviceCallbacks.cpp",
57      "main/DeviceCallbacks.cpp",
58      "main/DsoHack.cpp",
59      "main/chipinterface.cpp",
60      "main/Plug.cpp",
61    ]
62  }
63
64  output_name = "libMatterApp"
65  output_dir = "${root_out_dir}/lib"
66  complete_static_lib = true
67}
68
69group("default") {
70  deps = [ ":MatterApp" ]
71}
72
73config("config") {
74  include_dirs = [ "include" ]
75}

第40-49行主要包括了此Matter device的应用层代码。

第22-27行通过函数 chip_data_model 传入了zap配置文件。 因此需要将上一小节中创建的zap文件 on-off-plug.zap ,复制到改改目录下。 另外,需要目录 components/matter/connectedhomeip 中执行

./scripts/tools/zap/generate.py examples/on-off-plug/beken/on-off-plug.zap

这将会生成 on-off-plug.matter 文件。

编译过程中将会根据这个两个文件选择需要的cluster加入源码,并生成一些代码。关于这部分的原理,可以参考Matter 的文档 code_generation

实现相关代码

  1. 实现plug设备的基本操作,主要实现对插座设备的初始化开关等操作

Plug.cpp
 1#define KEY_GPIO        GPIO_24
 2#define CONTROL_GPIO    GPIO_26
 3#define LED_GPIO        GPIO_9
 4
 5void Plug::Init()
 6{
 7    ChipLogDetail(DeviceLayer,"Plug Init");
 8    gpio_config_t cfg;
 9	gpio_int_type_t int_type = GPIO_INT_TYPE_MAX;
10
11    bk_gpio_disable_input(CONTROL_GPIO);
12    bk_gpio_enable_output(CONTROL_GPIO);
13
14    bk_gpio_disable_input(LED_GPIO);
15    bk_gpio_enable_output(LED_GPIO);
16
17    cfg.io_mode =GPIO_INPUT_ENABLE;
18	int_type = GPIO_INT_TYPE_FALLING_EDGE;
19	cfg.pull_mode = GPIO_PULL_UP_EN;
20	bk_gpio_set_config(KEY_GPIO, &cfg);
21	bk_gpio_register_isr(KEY_GPIO ,key_callback);
22    bk_gpio_enable_interrupt(KEY_GPIO);
23
24    bk_gpio_set_output_high(CONTROL_GPIO);
25    bk_gpio_set_output_high(LED_GPIO);
26    isOn = false;
27    mFlashingFreq = 0;
28    initOver = false;
29}
30
31void Plug::StartUpInit()
32{
33    ChipLogDetail(DeviceLayer,"Plug StartUpInit");
34    if (Server::GetInstance().GetFabricTable().FabricCount() == 0)
35    {
36        LedStartFlashing(false);
37    }
38    initOver = true;
39}
40
41void Plug::SetOnOff(bool on)
42{
43    ChipLogDetail(DeviceLayer,"Plug SetOnOff");
44    if(!initOver || mFlashingFreq != 0 || on == isOn)
45    {
46        return;
47    }
  1. 实现Matter的回调,Matter协议接收到控制端相关属性的更改后,会调用对应的回调

DeviceCallbacks.cpp
 1void AppDeviceCallbacks::PostAttributeChangeCallback(EndpointId endpointId, ClusterId clusterId, AttributeId attributeId,
 2                                                     uint8_t type, uint16_t size, uint8_t * value)
 3{
 4    switch (clusterId)
 5    {
 6    case Clusters::OnOff::Id:
 7        OnOnOffPostAttributeChangeCallback(endpointId, attributeId, value);
 8        break;
 9    default:
10        ChipLogProgress(Zcl, "Unknown cluster ID: " ChipLogFormatMEI, ChipLogValueMEI(clusterId));
11        break;
12    }
13}
14void AppDeviceCallbacks::OnOnOffPostAttributeChangeCallback(EndpointId endpointId, AttributeId attributeId, uint8_t * value)
15{
16    VerifyOrExit(attributeId == Clusters::OnOff::Attributes::OnOff::Id,
17                 ChipLogError(DeviceLayer, "[%s] Unhandled Attribute ID: '0x%04lx", TAG, attributeId));
18    VerifyOrExit(endpointId == 1 || endpointId == 2,
19                 ChipLogError(DeviceLayer, "[%s] Unexpected EndPoint ID: `0x%02x'", TAG, endpointId));
20    PlugMgr().SetOnOff(*value);
21
22exit:
23    return;
24}
  1. 启动Matter进程,初始化并启动Matter CHIP进程

chipinterface.cpp
 1static AppDeviceCallbacks EchoCallbacks;
 2static void InitServer(intptr_t context)
 3{
 4    chip::BekenAppServer::Init();
 5    gExampleDeviceInfoProvider.SetStorageDelegate(&Server::GetInstance().GetPersistentStorage());
 6    chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider);
 7#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR    
 8    OTAHelpers::Instance().InitOTARequestor();
 9#endif    
10    PlugMgr().StartUpInit();
11}
12
13{
14    ChipLogProgress(DeviceLayer, "on-off-plug!");
15    chip::Inet::UDPEndPointImplLwIP::SetQueueFilter((chip::Inet::EndpointQueueFilter *)&filter);
16
17    CHIPDeviceManager & deviceMgr = CHIPDeviceManager::GetInstance();
18    err                           = deviceMgr.Init(&EchoCallbacks); // start the CHIP task
19    if (err != CHIP_NO_ERROR)
20    {
21        ChipLogError(DeviceLayer, "DeviceManagerInit() - ERROR!\r\n");
22    }
23    else
24    {
25        ChipLogProgress(DeviceLayer, "DeviceManagerInit() - OK\r\n");
26        vTaskDelay(pdMS_TO_TICKS(50)); // Just server the application event handler
27    ChipLogProgress(SoftwareUpdate, "Exited");

编译

修改对应的配置文件 projects/matter/config/bk7258/config 中的配置 CONFIG_MATTER_EXAMPLE="on-off-plug"

即可编译新建的Matter 应用

make bk7258 PROJECT=matter