| /* |
| * |
| * Copyright (c) 2021 Project CHIP Authors |
| * All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @file |
| * This file defines objects for a User-Directed Commissioning unsolicited |
| * initiator (client) and recipient (server). |
| * |
| */ |
| |
| #pragma once |
| |
| #include "UDCClients.h" |
| #include <lib/core/CHIPCore.h> |
| #include <lib/dnssd/Resolver.h> |
| #include <lib/support/CodeUtils.h> |
| #include <lib/support/DLLUtil.h> |
| #include <lib/support/logging/CHIPLogging.h> |
| #include <messaging/ExchangeContext.h> |
| #include <messaging/ExchangeMgr.h> |
| #include <messaging/Flags.h> |
| #include <protocols/Protocols.h> |
| #include <transport/TransportMgr.h> |
| |
| namespace chip { |
| namespace Protocols { |
| namespace UserDirectedCommissioning { |
| |
| inline constexpr char kProtocolName[] = "UserDirectedCommissioning"; |
| |
| // Cache contains 16 clients. This may need to be tweaked. |
| inline constexpr uint8_t kMaxUDCClients = 16; |
| |
| /** |
| * User Directed Commissioning Protocol Message Types |
| */ |
| enum class MsgType : uint8_t |
| { |
| IdentificationDeclaration = 0x00, |
| }; |
| |
| /** |
| * Represents the Identification Delaration message |
| * sent by a UDC client to a UDC server. |
| * |
| * ### IdentificationDeclaration format |
| * |
| * <pre> |
| * ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓ |
| * ┃ instance name '\n' ┃ ignore ┃ additional data TLV ┃ |
| * ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━┛ |
| * │← · · kInstanceNameMaxLength + 1 · · →│← TLV DataLength() →│ |
| * |
| * Commissioning kInstanceNameMaxLength is 16 |
| * </pre> |
| * |
| */ |
| class DLL_EXPORT IdentificationDeclaration |
| { |
| public: |
| constexpr static size_t kUdcTLVDataMaxBytes = 500; |
| |
| const char * GetInstanceName() const { return mInstanceName; } |
| void SetInstanceName(const char * instanceName) { Platform::CopyString(mInstanceName, instanceName); } |
| |
| bool HasDiscoveryInfo() { return mVendorId != 0 && mProductId != 0 && mCdPort != 0 && strlen(mDeviceName) > 0; } |
| |
| const char * GetDeviceName() const { return mDeviceName; } |
| void SetDeviceName(const char * deviceName) { Platform::CopyString(mDeviceName, deviceName); } |
| |
| uint16_t GetCdPort() const { return mCdPort; } |
| void SetCdPort(uint16_t port) { mCdPort = port; } |
| |
| uint16_t GetVendorId() const { return mVendorId; } |
| void SetVendorId(uint16_t vendorId) { mVendorId = vendorId; } |
| |
| uint16_t GetProductId() const { return mProductId; } |
| void SetProductId(uint16_t productId) { mProductId = productId; } |
| |
| const uint8_t * GetRotatingId() const { return mRotatingId; } |
| size_t GetRotatingIdLength() const { return mRotatingIdLen; } |
| void SetRotatingId(const uint8_t * rotatingId, size_t rotatingIdLen) |
| { |
| size_t maxSize = ArraySize(mRotatingId); |
| mRotatingIdLen = (maxSize < rotatingIdLen) ? maxSize : rotatingIdLen; |
| memcpy(mRotatingId, rotatingId, mRotatingIdLen); |
| } |
| |
| bool GetTargetAppInfo(uint8_t index, TargetAppInfo & info) const |
| { |
| if (index < mNumTargetAppInfos) |
| { |
| info.vendorId = mTargetAppInfos[index].vendorId; |
| info.productId = mTargetAppInfos[index].productId; |
| return true; |
| } |
| return false; |
| } |
| uint8_t GetNumTargetAppInfos() const { return mNumTargetAppInfos; } |
| |
| bool AddTargetAppInfo(TargetAppInfo vid) |
| { |
| if (mNumTargetAppInfos >= sizeof(mTargetAppInfos)) |
| { |
| // already at max |
| return false; |
| } |
| mTargetAppInfos[mNumTargetAppInfos].vendorId = vid.vendorId; |
| mTargetAppInfos[mNumTargetAppInfos].productId = vid.productId; |
| mNumTargetAppInfos++; |
| return true; |
| } |
| |
| const char * GetPairingInst() const { return mPairingInst; } |
| void SetPairingInst(const char * pairingInst) { Platform::CopyString(mPairingInst, pairingInst); } |
| |
| uint16_t GetPairingHint() const { return mPairingHint; } |
| void SetPairingHint(uint16_t pairingHint) { mPairingHint = pairingHint; } |
| |
| void SetNoPasscode(bool newValue) { mNoPasscode = newValue; }; |
| bool GetNoPasscode() const { return mNoPasscode; }; |
| |
| void SetCdUponPasscodeDialog(bool newValue) { mCdUponPasscodeDialog = newValue; }; |
| bool GetCdUponPasscodeDialog() const { return mCdUponPasscodeDialog; }; |
| |
| void SetCommissionerPasscode(bool newValue) { mCommissionerPasscode = newValue; }; |
| bool GetCommissionerPasscode() const { return mCommissionerPasscode; }; |
| |
| void SetCommissionerPasscodeReady(bool newValue) { mCommissionerPasscodeReady = newValue; }; |
| bool GetCommissionerPasscodeReady() const { return mCommissionerPasscodeReady; }; |
| |
| void SetCancelPasscode(bool newValue) { mCancelPasscode = newValue; }; |
| bool GetCancelPasscode() const { return mCancelPasscode; }; |
| |
| /** |
| * Writes the IdentificationDeclaration message to the given buffer. |
| * |
| * @return Total number of bytes written or 0 if an error occurred. |
| */ |
| uint32_t WritePayload(uint8_t * payloadBuffer, size_t payloadBufferSize); |
| |
| /** |
| * Reads the IdentificationDeclaration message from the given buffer. |
| */ |
| CHIP_ERROR ReadPayload(uint8_t * payloadBuffer, size_t payloadBufferSize); |
| |
| /** |
| * Assigns fields from this Identification Declaration to the given UDC client state. |
| */ |
| void UpdateClientState(UDCClientState * client) |
| { |
| client->SetDeviceName(GetDeviceName()); |
| client->SetVendorId(GetVendorId()); |
| client->SetProductId(GetProductId()); |
| client->SetRotatingId(GetRotatingId(), GetRotatingIdLength()); |
| client->SetPairingInst(GetPairingInst()); |
| client->SetPairingHint(GetPairingHint()); |
| for (uint8_t i = 0; i < GetNumTargetAppInfos(); i++) |
| { |
| TargetAppInfo info; |
| if (GetTargetAppInfo(i, info)) |
| { |
| client->AddTargetAppInfo(info); |
| } |
| } |
| |
| client->SetCdPort(GetCdPort()); |
| client->SetNoPasscode(GetNoPasscode()); |
| client->SetCdUponPasscodeDialog(GetCdUponPasscodeDialog()); |
| client->SetCommissionerPasscode(GetCommissionerPasscode()); |
| client->SetCommissionerPasscodeReady(GetCommissionerPasscodeReady()); |
| client->SetCancelPasscode(GetCancelPasscode()); |
| } |
| |
| void DebugLog() |
| { |
| ChipLogDetail(AppServer, "---- Identification Declaration Start ----"); |
| |
| ChipLogDetail(AppServer, "\tinstance: %s", mInstanceName); |
| if (strlen(mDeviceName) != 0) |
| { |
| ChipLogDetail(AppServer, "\tdevice Name: %s", mDeviceName); |
| } |
| if (mVendorId != 0) |
| { |
| ChipLogDetail(AppServer, "\tvendor id: %d", mVendorId); |
| } |
| if (mProductId != 0) |
| { |
| ChipLogDetail(AppServer, "\tproduct id: %d", mProductId); |
| } |
| if (mCdPort != 0) |
| { |
| ChipLogDetail(AppServer, "\tcd port: %d", mCdPort); |
| } |
| if (mRotatingIdLen > 0) |
| { |
| char rotatingIdString[chip::Dnssd::kMaxRotatingIdLen * 2 + 1] = ""; |
| Encoding::BytesToUppercaseHexString(mRotatingId, mRotatingIdLen, rotatingIdString, sizeof(rotatingIdString)); |
| ChipLogDetail(AppServer, "\trotating id: %s", rotatingIdString); |
| } |
| for (uint8_t i = 0; i < mNumTargetAppInfos; i++) |
| { |
| ChipLogDetail(AppServer, "\tapp vendor id / product id [%d]: %u/%u", i, mTargetAppInfos[i].vendorId, |
| mTargetAppInfos[i].productId); |
| } |
| if (strlen(mPairingInst) != 0) |
| { |
| ChipLogDetail(AppServer, "\tpairing instruction: %s", mPairingInst); |
| } |
| if (mPairingHint != 0) |
| { |
| ChipLogDetail(AppServer, "\tpairing hint: %d", mPairingHint); |
| } |
| |
| if (mNoPasscode) |
| { |
| ChipLogDetail(AppServer, "\tno passcode: true"); |
| } |
| if (mCdUponPasscodeDialog) |
| { |
| ChipLogDetail(AppServer, "\tcd upon passcode dialog: true"); |
| } |
| if (mCommissionerPasscode) |
| { |
| ChipLogDetail(AppServer, "\tcommissioner passcode: true"); |
| } |
| if (mCommissionerPasscodeReady) |
| { |
| ChipLogDetail(AppServer, "\tcommissioner passcode ready: true"); |
| } |
| if (mCancelPasscode) |
| { |
| ChipLogDetail(AppServer, "\tcancel passcode: true"); |
| } |
| ChipLogDetail(AppServer, "---- Identification Declaration End ----"); |
| } |
| |
| private: |
| // TODO: update spec per the latest tags |
| enum IdentificationDeclarationTLVTag |
| { |
| kVendorIdTag = 1, |
| kProductIdTag, |
| kDeviceNameTag, |
| kDeviceTypeTag, |
| kPairingInstTag, |
| kPairingHintTag, |
| kRotatingIdTag, |
| kCdPortTag, |
| kTargetAppListTag, |
| kTargetAppTag, |
| kAppVendorIdTag, |
| kAppProductIdTag, |
| kNoPasscodeTag, |
| kCdUponPasscodeDialogTag, |
| kCommissionerPasscodeTag, |
| kCommissionerPasscodeReadyTag, |
| kCancelPasscodeTag, |
| |
| kMaxNum = UINT8_MAX |
| }; |
| |
| char mInstanceName[Dnssd::Commission::kInstanceNameMaxLength + 1] = {}; |
| char mDeviceName[Dnssd::kMaxDeviceNameLen + 1] = {}; |
| uint16_t mCdPort = 0; |
| |
| uint16_t mVendorId = 0; |
| uint16_t mProductId = 0; |
| uint8_t mRotatingId[chip::Dnssd::kMaxRotatingIdLen]; |
| size_t mRotatingIdLen = 0; |
| |
| constexpr static size_t kMaxTargetAppInfos = 10; |
| uint8_t mNumTargetAppInfos = 0; // number of vendor Ids |
| TargetAppInfo mTargetAppInfos[kMaxTargetAppInfos]; |
| |
| char mPairingInst[chip::Dnssd::kMaxPairingInstructionLen + 1] = {}; |
| uint16_t mPairingHint = 0; |
| |
| bool mNoPasscode = false; |
| bool mCdUponPasscodeDialog = false; |
| bool mCommissionerPasscode = false; |
| bool mCommissionerPasscodeReady = false; |
| bool mCancelPasscode = false; |
| }; |
| |
| /** |
| * Represents the Commissioner Delaration message |
| * sent by a UDC server to a UDC client. |
| */ |
| class DLL_EXPORT CommissionerDeclaration |
| { |
| public: |
| enum class CdError : uint16_t |
| { |
| kNoError = 0, |
| kCommissionableDiscoveryFailed = 1, |
| kPaseConnectionFailed = 2, |
| kPaseAuthFailed = 3, |
| kDacValidationFailed = 4, |
| kAlreadyOnFabric = 5, |
| kOperationalDiscoveryFailed = 6, |
| kCaseConnectionFailed = 7, |
| kCaseAuthFailed = 8, |
| kConfigurationFailed = 9, |
| kBindingConfigurationFailed = 10, |
| kCommissionerPasscodeNotSupported = 11, |
| kInvalidIdentificationDeclarationParams = 12, |
| kAppInstallConsentPending = 13, |
| kAppInstalling = 14, |
| kAppInstallFailed = 15, |
| kAppInstalledRetryNeeded = 16, |
| kCommissionerPasscodeDisabled = 17, |
| kUnexpectedCommissionerPasscodeReady = 18 |
| }; |
| |
| constexpr static size_t kUdcTLVDataMaxBytes = 500; |
| |
| void SetErrorCode(CdError newValue) { mErrorCode = newValue; }; |
| CdError GetErrorCode() const { return mErrorCode; }; |
| |
| void SetNeedsPasscode(bool newValue) { mNeedsPasscode = newValue; }; |
| bool GetNeedsPasscode() const { return mNeedsPasscode; }; |
| |
| void SetNoAppsFound(bool newValue) { mNoAppsFound = newValue; }; |
| bool GetNoAppsFound() const { return mNoAppsFound; }; |
| |
| void SetPasscodeDialogDisplayed(bool newValue) { mPasscodeDialogDisplayed = newValue; }; |
| bool GetPasscodeDialogDisplayed() const { return mPasscodeDialogDisplayed; }; |
| |
| void SetCommissionerPasscode(bool newValue) { mCommissionerPasscode = newValue; }; |
| bool GetCommissionerPasscode() const { return mCommissionerPasscode; }; |
| |
| void SetQRCodeDisplayed(bool newValue) { mQRCodeDisplayed = newValue; }; |
| bool GetQRCodeDisplayed() const { return mQRCodeDisplayed; }; |
| |
| /** |
| * Writes the CommissionerDeclaration message to the given buffer. |
| * |
| * @return Total number of bytes written or 0 if an error occurred. |
| */ |
| uint32_t WritePayload(uint8_t * payloadBuffer, size_t payloadBufferSize); |
| |
| /** |
| * Reads the CommissionerDeclaration message from the given buffer. |
| */ |
| CHIP_ERROR ReadPayload(uint8_t * payloadBuffer, size_t payloadBufferSize); |
| |
| void DebugLog() |
| { |
| ChipLogDetail(AppServer, "---- Commissioner Declaration Start ----"); |
| |
| if (mErrorCode != CdError::kNoError) |
| { |
| ChipLogDetail(AppServer, "\terror code: %d", static_cast<uint16_t>(mErrorCode)); |
| } |
| |
| if (mNeedsPasscode) |
| { |
| ChipLogDetail(AppServer, "\tneeds passcode: true"); |
| } |
| if (mNoAppsFound) |
| { |
| ChipLogDetail(AppServer, "\tno apps found: true"); |
| } |
| if (mPasscodeDialogDisplayed) |
| { |
| ChipLogDetail(AppServer, "\tpasscode dialog displayed: true"); |
| } |
| if (mCommissionerPasscode) |
| { |
| ChipLogDetail(AppServer, "\tcommissioner passcode: true"); |
| } |
| if (mQRCodeDisplayed) |
| { |
| ChipLogDetail(AppServer, "\tQR code displayed: true"); |
| } |
| ChipLogDetail(AppServer, "---- Commissioner Declaration End ----"); |
| } |
| |
| private: |
| // TODO: update spec per the latest tags |
| enum CommissionerDeclarationTLVTag |
| { |
| kErrorCodeTag = 1, |
| kNeedsPasscodeTag, |
| kNoAppsFoundTag, |
| kPasscodeDialogDisplayedTag, |
| kCommissionerPasscodeTag, |
| kQRCodeDisplayedTag, |
| |
| kMaxNum = UINT8_MAX |
| }; |
| |
| CdError mErrorCode = CdError::kNoError; |
| bool mNeedsPasscode = false; |
| bool mNoAppsFound = false; |
| bool mPasscodeDialogDisplayed = false; |
| bool mCommissionerPasscode = false; |
| bool mQRCodeDisplayed = false; |
| }; |
| |
| class DLL_EXPORT InstanceNameResolver |
| { |
| public: |
| /** |
| * @brief |
| * Called when a UDC message is received specifying the given instanceName |
| * This method indicates that UDC Server needs the Commissionable Node corresponding to |
| * the given instance name to be found. UDC Server will wait for OnCommissionableNodeFound. |
| * |
| * @param instanceName DNS-SD instance name for the client requesting commissioning |
| * |
| */ |
| virtual void FindCommissionableNode(char * instanceName) = 0; |
| |
| virtual ~InstanceNameResolver() = default; |
| }; |
| |
| class DLL_EXPORT UserConfirmationProvider |
| { |
| public: |
| /** |
| * @brief |
| * Called when an Identification Declaration UDC message has been received |
| * and corresponding nodeData has been found. |
| * It is expected that the implementer will prompt the user to confirm their intention to |
| * commission the given node, and obtain the setup code to allow commissioning to proceed, |
| * and then invoke commissioning on the given Node (using CHIP Device Controller, for example) |
| * |
| * @param[in] state The state for the UDC Client. |
| * |
| */ |
| virtual void OnUserDirectedCommissioningRequest(UDCClientState state) = 0; |
| |
| virtual ~UserConfirmationProvider() = default; |
| }; |
| |
| class DLL_EXPORT CommissionerDeclarationHandler |
| { |
| public: |
| /** |
| * @brief |
| * Called when a Commissioner Declaration UDC message has been received. |
| * It is expected that the implementer will de-dup messages received from the |
| * same source within a short (1 second) time window. |
| * |
| * @param[in] source The source of the Commissioner Declaration Message. |
| * @param[in] cd The Commissioner Declaration Message. |
| * |
| */ |
| virtual void OnCommissionerDeclarationMessage(const chip::Transport::PeerAddress & source, CommissionerDeclaration cd) = 0; |
| |
| virtual ~CommissionerDeclarationHandler() = default; |
| }; |
| |
| /** |
| * TODO: |
| * - add processing of Commissioner Declaration flags |
| */ |
| class DLL_EXPORT UserDirectedCommissioningClient : public TransportMgrDelegate |
| { |
| public: |
| /** |
| * Send a User Directed Commissioning message to a CHIP node. |
| * |
| * @param transportMgr A transport to use for sending the message. |
| * @param idMessage The Identification Declaration message. |
| * @param peerAddress Address of destination. |
| * |
| * @return CHIP_ERROR_NO_MEMORY if allocation fails. |
| * Other CHIP_ERROR codes as returned by the lower layers. |
| * |
| */ |
| |
| CHIP_ERROR SendUDCMessage(TransportMgrBase * transportMgr, IdentificationDeclaration idMessage, |
| chip::Transport::PeerAddress peerAddress); |
| |
| /** |
| * Encode a User Directed Commissioning message. |
| * |
| * @param payload A PacketBufferHandle with the payload. |
| * |
| * @return CHIP_ERROR_NO_MEMORY if allocation fails. |
| * Other CHIP_ERROR codes as returned by the lower layers. |
| * |
| */ |
| |
| CHIP_ERROR EncodeUDCMessage(const System::PacketBufferHandle & payload); |
| |
| /** |
| * Set the listener to be called when a Commissioner Declaration UDC request is received. |
| * |
| * @param[in] commissionerDeclarationHandler The callback function to handle the message. |
| * |
| */ |
| void SetCommissionerDeclarationHandler(CommissionerDeclarationHandler * commissionerDeclarationHandler) |
| { |
| mCommissionerDeclarationHandler = commissionerDeclarationHandler; |
| } |
| |
| private: |
| void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf) override; |
| |
| CommissionerDeclarationHandler * mCommissionerDeclarationHandler = nullptr; |
| }; |
| |
| /** |
| * TODO: |
| * - add processing of Identification Declaration flags |
| */ |
| class DLL_EXPORT UserDirectedCommissioningServer : public TransportMgrDelegate |
| { |
| public: |
| /** |
| * Set the listener to be called when a UDC request is received |
| * and the Instance Name provided needs to be resolved. |
| * |
| * The resolver should call OnCommissionableNodeFound when the instance is found |
| * |
| * @param[in] instanceNameResolver The callback function to receive UDC request instance name. |
| * |
| */ |
| void SetInstanceNameResolver(InstanceNameResolver * instanceNameResolver) { mInstanceNameResolver = instanceNameResolver; } |
| |
| /** |
| * Set the listener to be called when a UDC request is received |
| * and the Instance Name has been resolved. |
| * |
| * The provider should prompt the user to allow commissioning of the node and provide the setup code. |
| * |
| * @param[in] userConfirmationProvider The callback function to obtain user confirmation. |
| * |
| */ |
| void SetUserConfirmationProvider(UserConfirmationProvider * userConfirmationProvider) |
| { |
| mUserConfirmationProvider = userConfirmationProvider; |
| } |
| |
| /** |
| * Update the processing state for a UDC Client based upon instance name. |
| * |
| * This can be used by the UX to set the state to one of the following values: |
| * - kUserDeclined |
| * - kObtainingOnboardingPayload |
| * - kCommissioningNode |
| * - kCommissioningFailed |
| * |
| * @param[in] instanceName The instance name for the UDC Client. |
| * @param[in] state The state for the UDC Client. |
| * |
| */ |
| void SetUDCClientProcessingState(char * instanceName, UDCClientProcessingState state); |
| |
| /** |
| * Reset the processing states for all UDC Clients |
| * |
| */ |
| void ResetUDCClientProcessingStates() { mUdcClients.ResetUDCClientStates(); } |
| |
| /** |
| * Called when a CHIP Node in commissioning mode is found. |
| * |
| * Lookup instanceName from nodeData in the active UDC Client states |
| * and if current state is kDiscoveringNode then change to kPromptingUser and |
| * call UX Prompt callback |
| * |
| * @param[in] nodeData DNS-SD response data. |
| * |
| */ |
| void OnCommissionableNodeFound(const Dnssd::DiscoveredNodeData & nodeData); |
| |
| /** |
| * Get the cache of UDC Clients |
| * |
| */ |
| UDCClients<kMaxUDCClients> & GetUDCClients() { return mUdcClients; } |
| |
| /** |
| * Print the cache of UDC Clients |
| * |
| */ |
| void PrintUDCClients(); |
| |
| /** |
| * Send a Commissioner Declaration message to the given peer address |
| * |
| * Only one message will be sent. |
| * Clients should follow spec and send up to 5 times with 100ms sleep between each call. |
| */ |
| CHIP_ERROR SendCDCMessage(CommissionerDeclaration cdMessage, chip::Transport::PeerAddress peerAddress); |
| |
| /** |
| * Encode a User Directed Commissioning message. |
| * |
| * @param payload A PacketBufferHandle with the payload. |
| * |
| * @return CHIP_ERROR_NO_MEMORY if allocation fails. |
| * Other CHIP_ERROR codes as returned by the lower layers. |
| * |
| */ |
| CHIP_ERROR EncodeUDCMessage(const System::PacketBufferHandle & payload); |
| |
| /** |
| * Assign the transport manager to use for Commissioner Declaration messages |
| */ |
| void SetTransportManager(TransportMgrBase * transportMgr) { mTransportMgr = transportMgr; } |
| |
| private: |
| InstanceNameResolver * mInstanceNameResolver = nullptr; |
| UserConfirmationProvider * mUserConfirmationProvider = nullptr; |
| |
| void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf) override; |
| |
| UDCClients<kMaxUDCClients> mUdcClients; // < Active UDC clients |
| |
| TransportMgrBase * mTransportMgr = nullptr; |
| }; |
| |
| } // namespace UserDirectedCommissioning |
| |
| template <> |
| struct MessageTypeTraits<UserDirectedCommissioning::MsgType> |
| { |
| static constexpr const Protocols::Id & ProtocolId() { return UserDirectedCommissioning::Id; } |
| |
| static auto GetTypeToNameTable() |
| { |
| static const std::array<MessageTypeNameLookup, 1> typeToNameTable = { |
| { |
| { UserDirectedCommissioning::MsgType::IdentificationDeclaration, "IdentificationDeclaration" }, |
| }, |
| }; |
| |
| return &typeToNameTable; |
| } |
| }; |
| |
| } // namespace Protocols |
| } // namespace chip |