Skip to content

Commit

Permalink
Add Commissioning State Machine
Browse files Browse the repository at this point in the history
The commissioning state machine is a short-lived object that is
instantiated to commission a given device, and then may be disposed when
this succeeds or fails.

The design uses the StateMachine utility in src/lib to provide an
extensible framework to consuming apps.  And it minimizes memory
footprint by maintaining only that state in memory that is currently
needed.

The state machine is provided as these primary resources:

* State.h, Event.h: common state and event templates
* Discoverer: a commissionable node discoverer
* ExampleCommissioningStateMachine.h: a concrete implementation that
  uses the states, events and discoverer to provide an example that apps
  can copy, modify, and extend

App implementations can add, remove and reorder states as needed.
Arbitrarily complex async UI logic can be realized with this design
without the need to define callback delegate interfaces in the sdk.

ExampleCommissioningStateMachine is integrated into chip-tool, providing
feature parity.  chip-tool uses the code to commission devices, and on
success then places them into a DeviceController for persistence and
subsequent interaction.

Fixes project-chip#7951
  • Loading branch information
msandstedt committed Feb 1, 2022
1 parent d6cb587 commit 7342ddb
Show file tree
Hide file tree
Showing 24 changed files with 2,900 additions and 91 deletions.
1 change: 1 addition & 0 deletions examples/chip-tool/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ static_library("chip-tool-utils") {
"${chip_root}/src/app/tests/suites/commands/log",
"${chip_root}/src/app/tests/suites/commands/system",
"${chip_root}/src/app/tests/suites/pics",
"${chip_root}/src/commissioner",
"${chip_root}/src/controller/data_model",
"${chip_root}/src/lib",
"${chip_root}/src/platform",
Expand Down
4 changes: 2 additions & 2 deletions examples/chip-tool/commands/common/CHIPCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ chip::FabricId CHIPCommand::CurrentCommissionerId()
return id;
}

chip::Controller::DeviceCommissioner & CHIPCommand::CurrentCommissioner()
chip::Controller::DeviceController & CHIPCommand::CurrentCommissioner()
{
auto item = mCommissioners.find(GetIdentity());
return *item->second.get();
Expand Down Expand Up @@ -212,7 +212,7 @@ CHIP_ERROR CHIPCommand::InitializeCommissioner(std::string key, chip::FabricId f
commissionerParams.operationalCredentialsDelegate = mCredIssuerCmds->GetCredentialIssuer();
commissionerParams.controllerVendorId = chip::VendorId::TestVendor1;

ReturnLogErrorOnFailure(DeviceControllerFactory::GetInstance().SetupCommissioner(commissionerParams, *(commissioner.get())));
ReturnLogErrorOnFailure(DeviceControllerFactory::GetInstance().SetupController(commissionerParams, *(commissioner.get())));
mCommissioners[key] = std::move(commissioner);

return CHIP_NO_ERROR;
Expand Down
2 changes: 1 addition & 1 deletion examples/chip-tool/commands/common/CHIPCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class CHIPCommand : public Command
{
public:
using ChipDevice = ::chip::DeviceProxy;
using ChipDeviceCommissioner = ::chip::Controller::DeviceCommissioner;
using ChipDeviceCommissioner = ::chip::Controller::DeviceController;
using ChipDeviceController = ::chip::Controller::DeviceController;
using IPAddress = ::chip::Inet::IPAddress;
using NodeId = ::chip::NodeId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,26 @@
*/

#include "DiscoverCommissionablesCommand.h"
#include <controller/CHIPDeviceControllerFactory.h>
#include <lib/support/BytesToHex.h>

using namespace ::chip;

CHIP_ERROR DiscoverCommissionablesCommand::RunCommand()
{
CurrentCommissioner().RegisterDeviceDiscoveryDelegate(this);
ReturnErrorOnFailure(
mDnsResolver.Init(chip::Controller::DeviceControllerFactory::GetInstance().GetSystemState()->UDPEndPointManager()));
mDnsResolver.SetResolverDelegate(this);
Dnssd::DiscoveryFilter filter(Dnssd::DiscoveryFilterType::kNone, (uint64_t) 0);
return CurrentCommissioner().DiscoverCommissionableNodes(filter);
ReturnErrorOnFailure(mDnsResolver.FindCommissionableNodes(filter));
return CHIP_NO_ERROR;
}

void DiscoverCommissionablesCommand::OnDiscoveredDevice(const chip::Dnssd::DiscoveredNodeData & nodeData)
void DiscoverCommissionablesCommand::OnNodeDiscoveryComplete(const chip::Dnssd::DiscoveredNodeData & nodeData)
{
nodeData.LogDetail();
}

void DiscoverCommissionablesCommand::OnNodeIdResolved(const chip::Dnssd::ResolvedNodeData & nodeData) {}

void DiscoverCommissionablesCommand::OnNodeIdResolutionFailed(const PeerId & peerId, CHIP_ERROR error) {}
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,21 @@

#include "../common/CHIPCommand.h"

class DiscoverCommissionablesCommand : public CHIPCommand, public chip::Controller::DeviceDiscoveryDelegate
class DiscoverCommissionablesCommand : public CHIPCommand, public chip::Dnssd::ResolverDelegate
{
public:
DiscoverCommissionablesCommand(CredentialIssuerCommands * credsIssuerConfig) : CHIPCommand("commissionables", credsIssuerConfig)
{}

/////////// DeviceDiscoveryDelegate Interface /////////
void OnDiscoveredDevice(const chip::Dnssd::DiscoveredNodeData & nodeData) override;
/////////// ResolverDelegate Interface /////////
void OnNodeIdResolved(const chip::Dnssd::ResolvedNodeData & nodeData) override;
void OnNodeIdResolutionFailed(const PeerId & peerId, CHIP_ERROR error) override;
void OnNodeDiscoveryComplete(const chip::Dnssd::DiscoveredNodeData & nodeData) override;

/////////// CHIPCommand Interface /////////
CHIP_ERROR RunCommand() override;
chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(30); }

private:
chip::Dnssd::ResolverProxy mDnsResolver;
};
131 changes: 72 additions & 59 deletions examples/chip-tool/commands/pairing/PairingCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "PairingCommand.h"
#include "platform/PlatformManager.h"
#include <controller/CHIPDeviceControllerFactory.h>
#include <controller/ExampleOperationalCredentialsIssuer.h>
#include <crypto/CHIPCryptoPAL.h>
#include <lib/core/CHIPSafeCasts.h>
Expand All @@ -29,10 +30,10 @@

using namespace ::chip;
using namespace ::chip::Controller;
using Commissionee = chip::Commissioner::Commissionee;

CHIP_ERROR PairingCommand::RunCommand()
{
CurrentCommissioner().RegisterPairingDelegate(this);
return RunInternal(mNodeId);
}

Expand Down Expand Up @@ -85,20 +86,51 @@ CommissioningParameters PairingCommand::GetCommissioningParameters()

CHIP_ERROR PairingCommand::PairWithQRCode(NodeId remoteId)
{
return CurrentCommissioner().PairDevice(remoteId, mOnboardingPayload);
auto stateMachine = Platform::MakeShared<CommissioningStateMachine>();
VerifyOrReturnError(stateMachine.get() != nullptr, CHIP_ERROR_NO_MEMORY);
auto onSuccess = [this, stateMachine](Commissionee & commissionee) { OnCommissioningComplete(*stateMachine.get()); };
auto onFailure = [this, stateMachine](Commissionee & commissionee) { OnCommissioningFailure(*stateMachine.get()); };
stateMachine.get()->Init(chip::Controller::DeviceControllerFactory::GetInstance().GetSystemState(), mCredIssuerCmds->GetCredentialIssuer(),
CurrentCommissioner().GetFabricIndex(), mNodeId, mOperationalDataset, mSSID, mPassword);
CHIP_ERROR err = stateMachine.get()->Commission(mOnboardingPayload, onSuccess, onFailure);
if (err != CHIP_NO_ERROR)
{
stateMachine.get()->Shutdown();
}
return err;
}

CHIP_ERROR PairingCommand::PairWithManualCode(NodeId remoteId)
{
return CurrentCommissioner().PairDevice(remoteId, mOnboardingPayload);
auto stateMachine = Platform::MakeShared<CommissioningStateMachine>();
VerifyOrReturnError(stateMachine.get() != nullptr, CHIP_ERROR_NO_MEMORY);
auto onSuccess = [this, stateMachine](Commissionee & commissionee) { OnCommissioningComplete(*stateMachine.get()); };
auto onFailure = [this, stateMachine](Commissionee & commissionee) { OnCommissioningFailure(*stateMachine.get()); };
stateMachine.get()->Init(chip::Controller::DeviceControllerFactory::GetInstance().GetSystemState(), mCredIssuerCmds->GetCredentialIssuer(),
CurrentCommissioner().GetFabricIndex(), mNodeId, mOperationalDataset, mSSID, mPassword);
CHIP_ERROR err = stateMachine.get()->Commission(mOnboardingPayload, onSuccess, onFailure);
if (err != CHIP_NO_ERROR)
{
stateMachine.get()->Shutdown();
}
return err;
}

CHIP_ERROR PairingCommand::Pair(NodeId remoteId, PeerAddress address)
{
RendezvousParameters params =
RendezvousParameters().SetSetupPINCode(mSetupPINCode).SetDiscriminator(mDiscriminator).SetPeerAddress(address);
CommissioningParameters commissioningParams = GetCommissioningParameters();
return CurrentCommissioner().PairDevice(remoteId, params, commissioningParams);
auto stateMachine = Platform::MakeShared<CommissioningStateMachine>();
VerifyOrReturnError(stateMachine.get() != nullptr, CHIP_ERROR_NO_MEMORY);
auto onSuccess = [this, stateMachine](Commissionee & commissionee) { OnCommissioningComplete(*stateMachine.get()); };
auto onFailure = [this, stateMachine](Commissionee & commissionee) { OnCommissioningFailure(*stateMachine.get()); };
stateMachine.get()->Init(chip::Controller::DeviceControllerFactory::GetInstance().GetSystemState(), mCredIssuerCmds->GetCredentialIssuer(),
CurrentCommissioner().GetFabricIndex(), mNodeId, mOperationalDataset, mSSID, mPassword);
CHIP_ERROR err =
stateMachine.get()->Commission(chip::RendezvousInformationFlag::kNone, mDiscriminator, mSetupPINCode, onSuccess, onFailure);
if (err != CHIP_NO_ERROR)
{
stateMachine.get()->Shutdown();
}
return err;
}

CHIP_ERROR PairingCommand::PairWithMdns(NodeId remoteId)
Expand All @@ -109,7 +141,18 @@ CHIP_ERROR PairingCommand::PairWithMdns(NodeId remoteId)
case chip::Dnssd::DiscoveryFilterType::kNone:
break;
case chip::Dnssd::DiscoveryFilterType::kShortDiscriminator:
case chip::Dnssd::DiscoveryFilterType::kLongDiscriminator:
case chip::Dnssd::DiscoveryFilterType::kLongDiscriminator: {
auto stateMachine = Platform::MakeShared<CommissioningStateMachine>();
VerifyOrReturnError(stateMachine.get() != nullptr, CHIP_ERROR_NO_MEMORY);
auto onSuccess = [this, stateMachine](Commissionee & commissionee) { OnCommissioningComplete(*stateMachine.get()); };
auto onFailure = [this, stateMachine](Commissionee & commissionee) { OnCommissioningFailure(*stateMachine.get()); };
stateMachine.get()->Init(chip::Controller::DeviceControllerFactory::GetInstance().GetSystemState(), mCredIssuerCmds->GetCredentialIssuer(),
CurrentCommissioner().GetFabricIndex(), mNodeId, mOperationalDataset, mSSID, mPassword);
CHIP_ERROR err =
stateMachine.get()->Commission(chip::RendezvousInformationFlag::kOnNetwork, static_cast<uint16_t>(mDiscoveryFilterCode),
mSetupPINCode, onSuccess, onFailure);
return err;
}
case chip::Dnssd::DiscoveryFilterType::kCompressedFabricId:
case chip::Dnssd::DiscoveryFilterType::kVendorId:
case chip::Dnssd::DiscoveryFilterType::kDeviceType:
Expand All @@ -126,84 +169,50 @@ CHIP_ERROR PairingCommand::PairWithMdns(NodeId remoteId)
break;
}

CurrentCommissioner().RegisterDeviceDiscoveryDelegate(this);
return CurrentCommissioner().DiscoverCommissionableNodes(filter);
ReturnErrorOnFailure(
mDnsResolver.Init(chip::Controller::DeviceControllerFactory::GetInstance().GetSystemState()->UDPEndPointManager()));
mDnsResolver.SetResolverDelegate(this);
ReturnErrorOnFailure(mDnsResolver.FindCommissionableNodes(filter));
return CHIP_NO_ERROR;
}

CHIP_ERROR PairingCommand::Unpair(NodeId remoteId)
{
CHIP_ERROR err = CurrentCommissioner().UnpairDevice(remoteId);
CurrentCommissioner().ReleaseOperationalDevice(remoteId);
CHIP_ERROR err = CHIP_NO_ERROR;
SetCommandExitStatus(err);
return err;
}

void PairingCommand::OnStatusUpdate(DevicePairingDelegate::Status status)
{
switch (status)
{
case DevicePairingDelegate::Status::SecurePairingSuccess:
ChipLogProgress(chipTool, "Secure Pairing Success");
break;
case DevicePairingDelegate::Status::SecurePairingFailed:
ChipLogError(chipTool, "Secure Pairing Failed");
break;
}
}

void PairingCommand::OnPairingComplete(CHIP_ERROR err)
{
if (err == CHIP_NO_ERROR)
{
ChipLogProgress(chipTool, "Pairing Success");
}
else
{
ChipLogProgress(chipTool, "Pairing Failure: %s", ErrorStr(err));
}

if (err != CHIP_NO_ERROR)
{
SetCommandExitStatus(err);
}
}

void PairingCommand::OnPairingDeleted(CHIP_ERROR err)
void PairingCommand::OnCommissioningComplete(CommissioningStateMachine & stateMachine)
{
CHIP_ERROR err = stateMachine.GrabCommissionee(CurrentCommissioner());
if (err == CHIP_NO_ERROR)
{
ChipLogProgress(chipTool, "Pairing Deleted Success");
ChipLogProgress(chipTool, "Device commissioning completed with success");
}
else
{
ChipLogProgress(chipTool, "Pairing Deleted Failure: %s", ErrorStr(err));
ChipLogProgress(chipTool, "Device commissioning Failure: %s", ErrorStr(err));
}

stateMachine.Shutdown();
SetCommandExitStatus(err);
}

void PairingCommand::OnCommissioningComplete(NodeId nodeId, CHIP_ERROR err)
void PairingCommand::OnCommissioningFailure(CommissioningStateMachine & stateMachine)
{
if (err == CHIP_NO_ERROR)
{
ChipLogProgress(chipTool, "Device commissioning completed with success");
}
else
{
ChipLogProgress(chipTool, "Device commissioning Failure: %s", ErrorStr(err));
}

SetCommandExitStatus(err);
ChipLogProgress(chipTool, "Device commissioning Failure");
SetCommandExitStatus(CHIP_ERROR_INTERNAL);
}

void PairingCommand::OnDiscoveredDevice(const chip::Dnssd::DiscoveredNodeData & nodeData)
void PairingCommand::OnNodeDiscoveryComplete(const chip::Dnssd::DiscoveredNodeData & nodeData)
{
const uint16_t port = nodeData.port;
char buf[chip::Inet::IPAddress::kMaxStringLength];
nodeData.ipAddress[0].ToString(buf);
ChipLogProgress(chipTool, "Discovered Device: %s:%u", buf, port);

// Stop Mdns discovery. Is it the right method ?
CurrentCommissioner().RegisterDeviceDiscoveryDelegate(nullptr);
mDnsResolver.Shutdown();

Inet::InterfaceId interfaceId = nodeData.ipAddress[0].IsIPv6LinkLocal() ? nodeData.interfaceId[0] : Inet::InterfaceId::Null();
PeerAddress peerAddress = PeerAddress::UDP(nodeData.ipAddress[0], port, interfaceId);
Expand All @@ -213,3 +222,7 @@ void PairingCommand::OnDiscoveredDevice(const chip::Dnssd::DiscoveredNodeData &
SetCommandExitStatus(err);
}
}

void PairingCommand::OnNodeIdResolved(const chip::Dnssd::ResolvedNodeData & nodeData) {}

void PairingCommand::OnNodeIdResolutionFailed(const PeerId & peerId, CHIP_ERROR error) {}
22 changes: 11 additions & 11 deletions examples/chip-tool/commands/pairing/PairingCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "../common/CHIPCommand.h"
#include <controller/CommissioningDelegate.h>
#include <commissioner/ExampleCommissioningStateMachine.h>
#include <zap-generated/CHIPClusters.h>

#include <commands/common/CredentialIssuerCommands.h>
Expand All @@ -45,10 +46,10 @@ enum class PairingNetworkType
Ethernet,
};

class PairingCommand : public CHIPCommand,
public chip::Controller::DevicePairingDelegate,
public chip::Controller::DeviceDiscoveryDelegate
class PairingCommand : public CHIPCommand, public chip::Dnssd::ResolverDelegate
{
using CommissioningStateMachine = chip::Commissioner::ExampleCommissioningStateMachine::ExampleCommissioningStateMachine;

public:
PairingCommand(const char * commandName, PairingMode mode, PairingNetworkType networkType,
CredentialIssuerCommands * credIssuerCmds,
Expand Down Expand Up @@ -134,14 +135,10 @@ class PairingCommand : public CHIPCommand,
CHIP_ERROR RunCommand() override;
chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(120); }

/////////// DevicePairingDelegate Interface /////////
void OnStatusUpdate(chip::Controller::DevicePairingDelegate::Status status) override;
void OnPairingComplete(CHIP_ERROR error) override;
void OnPairingDeleted(CHIP_ERROR error) override;
void OnCommissioningComplete(NodeId deviceId, CHIP_ERROR error) override;

/////////// DeviceDiscoveryDelegate Interface /////////
void OnDiscoveredDevice(const chip::Dnssd::DiscoveredNodeData & nodeData) override;
/////////// ResolverDelegate Interface /////////
void OnNodeIdResolved(const chip::Dnssd::ResolvedNodeData & nodeData) override;
void OnNodeIdResolutionFailed(const PeerId & peerId, CHIP_ERROR error) override;
void OnNodeDiscoveryComplete(const chip::Dnssd::DiscoveredNodeData & nodeData) override;

private:
CHIP_ERROR RunInternal(NodeId remoteId);
Expand All @@ -152,6 +149,8 @@ class PairingCommand : public CHIPCommand,
CHIP_ERROR PairWithCode(NodeId remoteId, chip::SetupPayload payload);
CHIP_ERROR Unpair(NodeId remoteId);
chip::Controller::CommissioningParameters GetCommissioningParameters();
void OnCommissioningComplete(CommissioningStateMachine & stateMachine);
void OnCommissioningFailure(CommissioningStateMachine & stateMachine);

const PairingMode mPairingMode;
const PairingNetworkType mNetworkType;
Expand All @@ -167,6 +166,7 @@ class PairingCommand : public CHIPCommand,
char * mOnboardingPayload;
uint64_t mDiscoveryFilterCode;
char * mDiscoveryFilterInstanceName;
chip::Dnssd::ResolverProxy mDnsResolver;

chip::CommissioneeDeviceProxy * mDevice;
chip::EndpointId mEndpointId = 0;
Expand Down
41 changes: 41 additions & 0 deletions src/commissioner/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright (c) 2020-2021 Project CHIP Authors
#
# 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.

import("//build_overrides/chip.gni")
import("//build_overrides/nlassert.gni")
import("${chip_root}/src/crypto/crypto.gni")
import("${chip_root}/src/platform/device.gni")

static_library("commissioner") {
output_name = "libCommissioner"

sources = [
"Commissionee.h",
"Discoverer.cpp",
"Discoverer.h",
"Events.h",
"ExampleCommissioningStateMachine.cpp",
"ExampleCommissioningStateMachine.h",
"States.h",
]

public_deps = [
"${chip_root}/src/controller",
"${chip_root}/src/lib/core",
"${chip_root}/src/lib/dnssd",
"${chip_root}/src/lib/support",
"${chip_root}/src/platform",
"${chip_root}/src/setup_payload",
]
}
Loading

0 comments on commit 7342ddb

Please sign in to comment.