matter源码分析之初始化

1. 前言

Matter的代码由Apple,Google,Silicon Labs,Amazon等大厂贡献,且由C++编写,当然不能错过学习大厂编写代码的机会,而且实现细节也吸引着我,所以开始阅读源码。

Matter的环境搭建见之前的文章Matter初体验

Matter源码庞大,编译后程序大小达到55M,为了更好的知道程序流转,使用VS Code的GDB可视化调试功能辅助阅读。在工程的lanuch.jsonconfigurations中新增以下内容,并选择Chiptool debug后按F5开始调试。

        {
            "name": "Chiptool debug",
            "type": "cppdbg",
            "request": "launch",
            "program": "/home/matter/connectedhomeip/out/debug/standalone/chip-tool",
            "args": ["onoff", "toggle", "1234", "1"],//传参
            "stopAtEntry": true,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ]
        },

建议在阅读源码前,按需食用以下知识:

右值引用与完美转发

泛化之美--C++11可变模版参数的妙用

模板全特化、偏特化、类型萃取

std::enable_if和SFINAE

2. main入口

文件examples/chip-tool/main.cpp

int main(int argc, char * argv[])
{
	/**注意与Command类区分*/
    Commands commands;
    
    /**对命令的预处理,注册命令*/
    registerCommandsDiscover(commands);
    registerCommandsPayload(commands);
    registerCommandsPairing(commands);
    registerCommandsReporting(commands);
    registerCommandsTests(commands);
    registerClusters(commands);/**注册cluster*/
    return commands.Run(argc, argv);/**初始化,程序运行*/
}

2.1 注册cluster

zzz_generated/chip-tool/zap-generated/cluster/Commands.h:57893

如:registerClusterOnOff,同时注册command命令,这些命令都使用类进行了封装,其基类为Command,都在Commands.h文件中

void registerClusterOnOff(Commands & commands)
{
    const char * clusterName = "OnOff";
    commands_list clusterCommands = {
        make_unique<OnOffOff>(),                      //
        ......
        make_unique<OnOffToggle>(),                   //
        ......
        make_unique<ReportOnOffClusterRevision>(),    //
    };
    commands.Register(clusterName, clusterCommands);
}

make_unique是一个模版,用于分配内存

template <typename T, typename... Args>
std::unique_ptr<Command> make_unique(Args &&... args)
{
    return std::unique_ptr<Command>(new T(std::forward<Args>(args)...));
}

2.1.1 cluster命令示例

class OnOffToggle : public ModelCommand
{
public:
    OnOffToggle() : ModelCommand("toggle") { ModelCommand::AddArguments(); }
    CHIP_ERROR SendCommand(ChipDevice * device, uint8_t endpointId) override
    {
        ChipLogProgress(chipTool, "Sending cluster (0x00000006) command (0x00000002) on endpoint %" PRIu8, endpointId);
        return chip::Controller::InvokeCommand(device, this, OnDefaultSuccess, OnDefaultFailure, endpointId, mRequest);
    }
private:
    chip::app::Clusters::OnOff::Commands::Toggle::Type mRequest;
};

2.2 文件和内存初始化部分调用流程

commands.Run(argc, argv)
    -->int Commands::Run(int argc, char ** argv)
        -->err = chip::Platform::MemoryInit();/**内存分配*/
        -->err = mStorage.Init();/**配置文件的加载及解析chip_tool_config.ini*/
        -->err = RunCommand(argc, argv);/**见下方分析*/

2.3 文件初始化

定义如下,默认参数为空,且程序没有传入,虽然可以传入,但是命名的只是后缀,如果想改存储目录,还是需要修改代码

CHIP_ERROR Init(const char * name = nullptr);
std::string GetFilename(const char * name)
{
    if (name == nullptr)
    {
        return "/tmp/chip_tool_config.ini";
    }
    return "/tmp/chip_tool_config." + std::string(name) + ".ini";
}

所以在目录下有时会看到两个配置文件,只有其中一个是正在使用的。比如我的就是使用的chip_tool_config.alpha.ini。定义在examples/chip-tool/commands/common/CHIPCommand.h中,暂且就叫发行版本定义。

constexpr const char kIdentityAlpha[] = "alpha";
constexpr const char kIdentityBeta[]  = "beta";
constexpr const char kIdentityGamma[] = "gamma";

2.4 Command部分解析

examples/chip-tool/commands/common/Commands.cpp:117

//执行 ./chip-tool onoff toggle 1234 1
CHIP_ERROR Commands::RunCommand(int argc, char ** argv)
{
    std::map<std::string, CommandsVector>::iterator cluster;
    Command * command = nullptr;
    ......
    cluster = GetCluster(argv[1]);//根据cluster名字获取指针
    ......
    if (!IsGlobalCommand(argv[2]))//read write report是global的
    {
        command = GetCommand(cluster->second, argv[2]);//取出
        if (command == nullptr)
        {
            ChipLogError(chipTool, "Unknown command: %s", argv[2]);
            ShowCluster(argv[0], argv[1], cluster->second);
            return CHIP_ERROR_INVALID_ARGUMENT;
        }
    }
    else{
        ......
    }
    return command->Run();
}

最重要的就是command->Run();之后的流程。

2.5 总调用流程

/**CHIPCommand::Run()*/
command->Run()
    -->mDefaultStorage.Init()/**配置文件读取*/
        -->PersistentStorage::Init(const char * name)
    -->mFabricStorage.Initialize(&mDefaultStorage)/**Fabric storage 读取*/
        -->CHIP_ERROR Initialize(PersistentStorageDelegate * storage)
    -->listenport初始化 /**见下方 IPV6部分端口初始化 节详解*/
    /**初始化大类1 DeviceControllerFactory::GetInstance().Init(factoryInitParams)*/
    -->CHIP_ERROR DeviceControllerFactory::Init(FactoryInitParams params)
        -->CHIP_ERROR err = InitSystemState(params)/**见下方第3章详解*/
                /**DeviceLayer::PlatformMgr().InitChipStack();*/
                -->inline CHIP_ERROR PlatformManager::InitChipStack()
                    /**平台初始化,包括信号接管,GDBus IPC通信、Glib 事件线程、netlink初始化*/
                    -->CHIP_ERROR PlatformManagerImpl::_InitChipStack()
                        /**除下放功能,还有条件变量和互斥锁的初始化*/
                        -->CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_InitChipStack()
                            /**LOG、CHIP system layer、Configuration Manager、CHIP Inet layer、
                             * BLE manager、Connectivity Manager object、NFC Manager。
                             * 因为需要文件和设备操作,所以需要sudo权限 */
                            -->CHIP_ERROR GenericPlatformManagerImpl<ImplClass>::_InitChipStack()             
       -->stateParams.transportMgr->Init(...)/**见下方3.2详解*/
       -->stateParams.fabricTable->Init(mFabricStorage)/**见下方3.3详解*/
           -->LoadFromStorage(fabric)
       -->stateParams.sessionMgr->Init()/**GlobalEncryptedMessageCounter init*/
   /**初始化大类2 InitializeCommissioner(GetIdentity(), CurrentCommissionerIndex())*/                     
   -->CHIP_ERROR CHIPCommand::InitializeCommissioner(std::string key, chip::FabricId fabricId)/**见下方第4章详解*/

可以看出东西还是比较多的,下面开始详细分析。

3. System State Initialized的初始化

本部分主要是对系统资源、配置文件读取等的初始化

3.1 扩展阅读

Glib g_main_loop_new

GDBus

配置文件,系统相关初始化比较简单,可以自行阅读。

3.2 stateParams.transportMgr->Init

这个类中的方法,如初始化网络等,内部比较复杂,尤其是UDP类的多层构造和获取,比较绕

{
    stateParams.transportMgr = chip::Platform::New<DeviceTransportMgr>();/**new*/
    
    ReturnErrorOnFailure(stateParams.transportMgr->Init(
                    Transport::UdpListenParameters(stateParams.inetLayer).SetAddressType(Inet::IPAddressType::kIPv6).SetListenPort(mListenPort)
#if INET_CONFIG_ENABLE_IPV4
            ,
        Transport::UdpListenParameters(stateParams.inetLayer).SetAddressType(Inet::IPAddressType::kIPv4).SetListenPort(mListenPort)
#endif
#if CONFIG_NETWORK_LAYER_BLE
            ,
        Transport::BleListenParameters(stateParams.bleLayer)
#endif
            ));
}

stateParams.transportMgr->Init是new出来的DeviceTransportMgr,我们来看看这是什么。

在命名空间chip中,DeviceTransportMgr使用using关键字修饰,作用类似typedef,实际是TransportMgr类的。

namespace chip {
......
using DeviceTransportMgr = TransportMgr<Transport::UDP /* IPv6 */
#if INET_CONFIG_ENABLE_IPV4
                                        ,
                                        Transport::UDP /* IPv4 */
#endif
#if CONFIG_NETWORK_LAYER_BLE
                                        ,
                                        Transport::BLE<kMaxDeviceTransportBlePendingPackets> /* BLE */
#endif
                                        >;
......
}

我看到类TransportMgr是可变参数模板,这样我们就能理解stateParams.transportMgr->Init的传参了

template <typename... TransportTypes>/**前向声明*/
class TransportMgr : public TransportMgrBase
{
public:
    template <typename... Args>//基本定义
    CHIP_ERROR Init(Args &&... transportInitArgs)
    {
        ReturnErrorOnFailure(mTransport.Init(this, std::forward<Args>(transportInitArgs)...));
        return TransportMgrBase::Init(&mTransport);
    }
    ......
}

3.2.1 本部分调用流程

CHIP_ERROR Init(Args &&... transportInitArgs)
    -->mTransport.Init(this, std::forward<Args>(transportInitArgs)...)
        -->CHIP_ERROR Init(RawTransportDelegate * delegate, Args &&... args)
            -->return InitImpl(delegate, std::forward<Args>(args)...);
                -->CHIP_ERROR InitImpl(RawTransportDelegate * delegate, InitArg && arg, Rest &&... rest)
                    -->CHIP_ERROR UDP::Init(UdpListenParameters & params)/**见下方UDP初始化节*/
    -->CHIP_ERROR TransportMgrBase::Init(Transport::Base * transport)

src/transport/raw/Tuple.h:219 递归函数方式展开参数包

/**
* Initialization method that forwards arguments for initialization to each of the underlying
* transports.
*
* Transports are assumed to have an Init call with EXACTLY one argument. This method MUST initialize
* all underlying transports.
*
* @param delegate the delegate to handle messages.
* @param args     initialization arguments, forwarded as-is to the underlying transports.
*/
template <typename... Args, typename std::enable_if<(sizeof...(Args) == sizeof...(TransportTypes))>::type * = nullptr>
CHIP_ERROR Init(RawTransportDelegate * delegate, Args &&... args)
{
    return InitImpl(delegate, std::forward<Args>(args)...);
}
/**
 * Recursive init implementation iterating through transport members
 *
 * Given a set of arguments 'a1, a2, a3, ... aN' will call an Init method on the last N
 * transports.
 *
 * Method is expected to be called initially with exactly sizeof(TransportTypes) to initialize
 * all transports.
 *
 * @param arg the next initialize argument to pass to the transport Init method
 * @param rest tail arguments to be passed to the rest of transport Init methods.
 */    
template <typename InitArg, typename... Rest>
CHIP_ERROR InitImpl(RawTransportDelegate * delegate, InitArg && arg, Rest &&... rest)
{
    auto transport = &std::get<sizeof...(TransportTypes) - sizeof...(Rest) - 1>(mTransports);/**怎么转换到UDP类的?*/
    CHIP_ERROR err = transport->Init(std::forward<InitArg>(arg));
    if (err != CHIP_NO_ERROR)
    {
        return err;
    }
    transport->SetDelegate(delegate);
    return InitImpl(delegate, std::forward<Rest>(rest)...);/**递归函数方式展开参数包*/
}

3.2.2 蓝牙部分

显示声明构造函数

class BleListenParameters
{
public:
    explicit BleListenParameters(Ble::BleLayer * layer) : mLayer(layer) {}
    ......
}

3.2.3 IPV6部分

端口的由来:

CHIP_ERROR CHIPCommand::Run()
{
    ......
    factoryInitParams.listenPort    = static_cast<uint16_t>(mDefaultStorage.GetListenPort() + CurrentCommissionerIndex());
    ......
}

其中mDefaultStorage.GetListenPort() 方法中计算端口号,默认为5541。接着调用SyncGetKeyValue从字段ListenPort中读取,不存在将会直接返回。

uint16_t PersistentStorage::GetListenPort()
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    // By default chip-tool listens on CHIP_PORT + 1. This is done in order to avoid
    // having 2 servers listening on CHIP_PORT when one runs an accessory server locally.
    uint16_t chipListenPort = static_cast<uint16_t>(CHIP_PORT + 1);
    char value[6];
    uint16_t size = static_cast<uint16_t>(sizeof(value));
    err           = SyncGetKeyValue(kPortKey, value, size);
    ......
    return chipListenPort;
}

接着计算偏移,是根据发行版本不同进行的偏移,可以方便测试。最终得到端口5542

uint16_t CHIPCommand::CurrentCommissionerIndex()
{
    uint16_t index = 0;
    std::string name = GetIdentity();
    if (name.compare(kIdentityAlpha) == 0)/** alpha */
    {
        index = kIdentityAlphaFabricId;/** 1 */
    }
    else if (name.compare(kIdentityBeta) == 0)
    {
        index = kIdentityBetaFabricId;/** 2 */
    }
    else if (name.compare(kIdentityGamma) == 0)
    {
        index = kIdentityGammaFabricId;/** 3 */
    }
    VerifyOrDieWithMsg(index != 0, chipTool, "Unknown commissioner name: %s. Supported names are [%s, %s, %s]", name.c_str(),
                       kIdentityAlpha, kIdentityBeta, kIdentityGamma);
    return index;
}
std::string CHIPCommand::GetIdentity()
{
    std::string name = mCommissionerName.HasValue() ? mCommissionerName.Value() : kIdentityAlpha;/** alpha */
    if (name.compare(kIdentityAlpha) != 0 && name.compare(kIdentityBeta) != 0 && name.compare(kIdentityGamma) != 0)
    {
        ChipLogError(chipTool, "Unknown commissioner name: %s. Supported names are [%s, %s, %s]", name.c_str(), kIdentityAlpha,
                     kIdentityBeta, kIdentityGamma);
        chipDie();
    }
    return name;
}

UDP初始化

上面说到InitImpl方法内transport->Init(std::forward<InitArg>(arg))的实际调用是UDP::Init,我们看看UDP初始化做了什么。

src/transport/raw/UDP.cpp:40

CHIP_ERROR UDP::Init(UdpListenParameters & params)
    -->CHIP_ERROR UDPEndPoint::Bind(IPAddressType addrType, const IPAddress & addr, uint16_t port, InterfaceId intfId)
        -->CHIP_ERROR UDPEndPointImplSockets::BindImpl(IPAddressType addressType, const IPAddress & addr, uint16_t port, InterfaceId interface)
            -->CHIP_ERROR UDPEndPointImplSockets::BindImpl(IPAddressType addressType, const IPAddress & addr, uint16_t port, InterfaceId interface)
                -->CHIP_ERROR IPv6Bind(int socket, const IPAddress & address, uint16_t port, InterfaceId interface)
    -->CHIP_ERROR UDPEndPoint::Listen(OnMessageReceivedFunct onMessageReceived, OnReceiveErrorFunct onReceiveError, void * appState)
        -->CHIP_ERROR UDPEndPointImplSockets::ListenImpl()/**里面的实现没有看懂*/

3.3 stateParams.fabricTable->Init

定义

CHIP_ERROR FabricTable::Init(FabricStorage * storage)
    -->LoadFromStorage(fabric)/**加载信息*/

定义了最多能接受的Fabric数量

#define CHIP_CONFIG_MAX_DEVICE_ADMINS 16
CHIP_ERROR FabricInfo::LoadFromStorage(FabricStorage * storage)
{
    char key[kKeySize];
    /**结果 key=Fabric1 */
    ReturnErrorOnFailure(GenerateKey(mFabric, key, sizeof(key)));/**kFabricTableKeyPrefix 固定前缀*/
    ......
    /**原型SimpleFabricStorage::SyncLoad(FabricIndex fabricIndex, const char * key, void * buffer, uint16_t & size)
    * 没有读取到会退出,要是读取到则会进行下面的数据处理
    */
    SuccessOrExit(err = storage->SyncLoad(mFabric, key, info, infoSize));
    ......
    SetRootCert(ByteSpan(info->mRootCert, rootCertLen))
    ......
}
CHIP_ERROR SimpleFabricStorage::SyncLoad(FabricIndex fabricIndex, const char * key, void * buffer, uint16_t & size)
{
    VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
    char formattedKey[MAX_KEY_SIZE] = "";
    /**最终结果:F01/Fabric1 */
    ReturnErrorOnFailure(formatKey(fabricIndex, MutableCharSpan(formattedKey, MAX_KEY_SIZE), key));
    /**去配置文件中找,我的配置文件中是没有的*/
    return mStorage->SyncGetKeyValue(formattedKey, buffer, size);
};

4. Commissioner的初始化

InitializeCommissioner(GetIdentity(), CurrentCommissionerIndex())
//原型CHIP_ERROR CHIPCommand::InitializeCommissioner(std::string key, chip::FabricId fabricId)

入参就是"alpha"1

4.1 调用流程

InitializeCommissioner(GetIdentity(), CurrentCommissionerIndex())
    -->ephemeralKey.Initialize()/**P256v1加密初始化*/
    -->mCommissionerStorage.Init(key.c_str())/**配置文件初始化*/
    /**读取配置文件中的pairkey,如果不存在,则创建,可以自定义key
    * 加密由Openssl提供,是库的方式使用,计算出value,将value进行base64后存入
    */
    -->mOpCredsIssuer.Initialize()
    /**生成NOC、ICAC
    * 从chip_tool_config.alpha.ini中读取
    * ExampleOpCredsCAKey,ExampleOpCredsICAKey,ExampleCARootCert
    */
    -->mOpCredsIssuer.GenerateNOCChainAfterValidation()
    /**CHIP_ERROR DeviceControllerFactory::SetupCommissioner(SetupParams params, DeviceCommissioner & commissioner)*/
    -->DeviceControllerFactory::GetInstance().SetupCommissioner(commissionerParams, *(commissioner.get()))
        -->InitSystemState()/**已经初始化完成,内部赋值指针后退出*/
        -->PopulateInitParams(commissionerParams, params);/**参数赋值*/
        /**CHIP_ERROR DeviceCommissioner::Init(CommissionerInitParams params)*/
        -->commissioner.Init(commissionerParams)
            /**DeviceController::Init(ControllerInitParams params)*/
            -->DeviceController::Init(params)
                -->系统初始化验证
                /**InitDataModelHandler(chip::Messaging::ExchangeManager * exchangeManager)*/
                -->InitDataModelHandler(params.systemState->ExchangeMgr())
                    /**ZCL ZAP数据模型的初始化*/
                    -->emberAfEndpointConfigure()
                    -->emberAfInit(exchangeManager)
                -->ProcessControllerNOCChain(params)
                    -->/**Convert standard X.509 certificate to CHIP certificate.*/
                    -->/**Storage of NOC and Root Cert in FabricInfo.*/
                    /**FabricInfo::SetFabricInfo(FabricInfo & newFabric)
                    * 证书链的构建和验证
                    */
                    -->fabric->SetFabricInfo(newFabric)
                        -->VerifyCredentials(newFabric.mNOCCert, newFabric.mICACert, validContext, mOperationalId, mFabricId, pubkey)
                            -->certificates.LoadCert(mRootCert, BitFlags<CertDecodeFlags>(CertDecodeFlags::kIsTrustAnchor))
                                -->Enter the certificate structure
                                -->reader.EnterContainer(containerType)
                                /** Decode and convert the To-Be-Signed (TBS) portion of the CHIP certificate into X.509 DER encoded form.*/
                                -->DecodeConvertTBSCert(reader, writer, cert)
                                /** Verify the cert has both the Subject Key Id and Authority Key Id extensions present. */
                                -->cert.mCertFlags.HasAll(CertFlags::kExtPresent_SubjectKeyId, CertFlags::kExtPresent_AuthKeyId)
                                /** Decode the certificate's signature */
                                -->DecodeECDSASignature(reader, cert)
                                /** Verify no more elements in the certificate. */
                                -->reader.VerifyEndOfContainer()
                                -->//检查是否证书已经存在,空间检查,new保存
                            /**检查加载的证书链 (noc -> icac -> mRootCert)*/
                            -->certificates.FindValidCert(nocSubjectDN, nocSubjectKeyId, context, &resultCert)
                            /**从 TLV 编码形式的操作证书中提取Node ID and Fabric ID*/
                            -->ExtractNodeIdFabricIdFromOpCert(certificates.GetLastCert()[0], &nodeId, &fabricId)
                            -->GetCompressedId(fabricId, nodeId, &nocPeerId)
                                /**获取root pubkey*/
                                -->P256PublicKey rootPubkey(GetRootPubkey());
                                /*GenerateCompressedFabricId(const Crypto::P256PublicKey & root_public_key, uint64_t fabric_id,MutableByteSpan & out_compressed_fabric_id)
                                * 从节点的根公钥和结构 ID 计算用于操作发现服务记录的压缩结构标识符。 成功后,out_compressed_fabric_id 的大小将恰好为 kCompressedFabricIdentifierSize。
                                * 还不太理解怎么算的
                                */
                                -->GenerateCompressedFabricId(rootPubkey, fabricId, compressedFabricIdSpan)
                                -->设置compressedFabricId和nodeId
                       -->设置正式、FabricId、nodeId等
               -->参数指针赋值            

void InitDataModelHandler(chip::Messaging::ExchangeManager * exchangeManager)中就是芯科的ZCL部分代码,C语言编写

证书的读取作为一个单独功能,使用TLV存储,经过转换存储在ChipCertificateData

-->certificates.LoadCert(mRootCert, BitFlags<CertDecodeFlags>(CertDecodeFlags::kIsTrustAnchor))
    /**Enter the certificate structure*/
    -->reader.EnterContainer(containerType)
    /** Decode and convert the To-Be-Signed (TBS) portion of the CHIP certificate into X.509 DER encoded form.*/
    -->DecodeConvertTBSCert(reader, writer, cert)
    /** Verify the cert has both the Subject Key Id and Authority Key Id extensions present. */
    -->cert.mCertFlags.HasAll(CertFlags::kExtPresent_SubjectKeyId, CertFlags::kExtPresent_AuthKeyId)
    /** Decode the certificate's signature */
    -->DecodeECDSASignature(reader, cert)
    /** Verify no more elements in the certificate. */
    -->reader.VerifyEndOfContainer()
    -->//检查是否证书已经存在,空间检查,new保存
/**证书存储数据结构*/
struct ChipCertificateData
{
    ChipCertificateData();
    ~ChipCertificateData();
    void Clear();
    bool IsEqual(const ChipCertificateData & other) const;
    ByteSpan mCertificate;                      /**< Original raw buffer data. */
    ChipDN mSubjectDN;                          /**< Certificate Subject DN. */
    ChipDN mIssuerDN;                           /**< Certificate Issuer DN. */
    CertificateKeyId mSubjectKeyId;             /**< Certificate Subject public key identifier. */
    CertificateKeyId mAuthKeyId;                /**< Certificate Authority public key identifier. */
    uint32_t mNotBeforeTime;                    /**< Certificate validity: Not Before field. */
    uint32_t mNotAfterTime;                     /**< Certificate validity: Not After field. */
    P256PublicKeySpan mPublicKey;               /**< Certificate public key. */
    uint16_t mPubKeyCurveOID;                   /**< Public key Elliptic Curve CHIP OID. */
    uint16_t mPubKeyAlgoOID;                    /**< Public key algorithm CHIP OID. */
    uint16_t mSigAlgoOID;                       /**< Certificate signature algorithm CHIP OID. */
    BitFlags<CertFlags> mCertFlags;             /**< Certificate data flags. */
    BitFlags<KeyUsageFlags> mKeyUsageFlags;     /**< Certificate key usage extensions flags. */
    BitFlags<KeyPurposeFlags> mKeyPurposeFlags; /**< Certificate extended key usage extensions flags. */
    uint8_t mPathLenConstraint;                 /**< Basic constraint: path length. */
    P256ECDSASignatureSpan mSignature;          /**< Certificate signature. */
    uint8_t mTBSHash[Crypto::kSHA256_Hash_Length]; /**< Certificate TBS hash. */
};

5. 总结

Matter的初始化流程还是比较复杂的,在阅读后仍然有一些不太懂的地方或者错误的地方,有知道的大神希望能够指点指点。

代码编写使用了很多C++11的特性,尤其广泛使用可变参数模板,代码规范度很高,是很好的学习材料。

下面将阅读配对入网过程。

posted @ 2023-02-19 21:16  小满的博客  阅读(286)  评论(0编辑  收藏  举报