Skip to content

Commit

Permalink
[darwin-framework-tool] Add discover module to scan and list the disc…
Browse files Browse the repository at this point in the history
…overed commissionable devices over BLE and Mdns (#27318)

* Update the SetUpCodePairer such that additional CommonResolutionData can be added when discovered over the network

* [matter framework] Add MTRDeviceControllerFactory::startScan and MTRDeviceControllerFactory::stopScan

[matter framework] Add MTRDeviceController::setupCommissiongSessionWithDiscoveredDevice

* [darwin-framework-tool] Add discover module to scan and list the discovered commissionable devices over BLE and Mdns

[darwin-framework-tool] Add pairing by-index command to commission a discovered device

* [Typo] Rename an argument in the documentation of src/lib/dnssd/platform/Dnssd.h from interfaceId to interface
  • Loading branch information
vivien-apple authored and pull[bot] committed Apr 8, 2024
1 parent ebc79e1 commit 1325997
Show file tree
Hide file tree
Showing 20 changed files with 841 additions and 15 deletions.
3 changes: 3 additions & 0 deletions examples/darwin-framework-tool/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ executable("darwin-framework-tool") {
"commands/common/MTRError.mm",
"commands/common/MTRError_Utils.h",
"commands/common/MTRLogging.h",
"commands/discover/Commands.h",
"commands/discover/DiscoverCommissionablesCommand.h",
"commands/discover/DiscoverCommissionablesCommand.mm",
"commands/pairing/Commands.h",
"commands/pairing/DeviceControllerDelegateBridge.mm",
"commands/pairing/GetCommissionerNodeIdCommand.h",
Expand Down
36 changes: 36 additions & 0 deletions examples/darwin-framework-tool/commands/discover/Commands.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2023 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.
*
*/

#pragma once

#import <Matter/Matter.h>

#include "DiscoverCommissionablesCommand.h"

void registerCommandsDiscover(Commands & commands)
{
const char * clusterName = "Discover";

commands_list clusterCommands = {
make_unique<DiscoverCommissionablesStartCommand>(),
make_unique<DiscoverCommissionablesStopCommand>(),
make_unique<DiscoverCommissionablesListCommand>(),
};

commands.Register(clusterName, clusterCommands);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2023 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.
*
*/

#include "../common/CHIPCommandBridge.h"

class DiscoverCommissionablesStartCommand : public CHIPCommandBridge
{
public:
DiscoverCommissionablesStartCommand() : CHIPCommandBridge("start") {}

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

class DiscoverCommissionablesStopCommand : public CHIPCommandBridge
{
public:
DiscoverCommissionablesStopCommand() : CHIPCommandBridge("stop") {}

protected:
/////////// CHIPCommandBridge Interface /////////
CHIP_ERROR RunCommand() override;
chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(1); }
};

class DiscoverCommissionablesListCommand : public CHIPCommandBridge
{
public:
DiscoverCommissionablesListCommand() : CHIPCommandBridge("list") {}

protected:
/////////// CHIPCommandBridge Interface /////////
CHIP_ERROR RunCommand() override;
chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(1); }
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2023 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.
*
*/
#include "DiscoverCommissionablesCommand.h"

NSMutableArray * gDiscoveredDevices = [[NSMutableArray alloc] init];
auto gDispatchQueue = dispatch_queue_create("com.chip.discover", DISPATCH_QUEUE_SERIAL);

@interface DeviceScannerDelegate : NSObject <MTRCommissionableBrowserDelegate>
- (void)didDiscoverCommissionable:(MTRCommissionableBrowserResult *)device;
- (void)commissionableUnavailable:(MTRCommissionableBrowserResult *)device;
@end

@implementation DeviceScannerDelegate
- (void)didDiscoverCommissionable:(MTRCommissionableBrowserResult *)device
{
auto serviceName = device.serviceName;
auto vendorId = device.vendorId;
auto productId = device.productId;
auto discriminator = device.discriminator;
[gDiscoveredDevices addObject:device];

NSLog(@"Found Device (%@) with discriminator: %@ (vendor: %@, product: %@)", serviceName, discriminator, vendorId, productId);
}

- (void)commissionableUnavailable:(MTRCommissionableBrowserResult *)device
{
auto serviceName = device.serviceName;
auto vendorId = device.vendorId;
auto productId = device.productId;
auto discriminator = device.discriminator;
[gDiscoveredDevices removeObjectIdenticalTo:device];

NSLog(@"Removed Device (%@) with discriminator: %@ (vendor: %@, product: %@)", serviceName, discriminator, vendorId, productId);
}
@end

CHIP_ERROR DiscoverCommissionablesStartCommand::RunCommand()
{
VerifyOrReturnError(IsInteractive(), CHIP_ERROR_INCORRECT_STATE);

dispatch_sync(gDispatchQueue, ^{
[gDiscoveredDevices removeAllObjects];
});

auto delegate = [[DeviceScannerDelegate alloc] init];
auto success = [CurrentCommissioner() startScan:delegate queue:gDispatchQueue];
VerifyOrReturnError(success, CHIP_ERROR_INTERNAL);

SetCommandExitStatus(CHIP_NO_ERROR);
return CHIP_NO_ERROR;
}

CHIP_ERROR DiscoverCommissionablesStopCommand::RunCommand()
{
VerifyOrReturnError(IsInteractive(), CHIP_ERROR_INCORRECT_STATE);

auto success = [CurrentCommissioner() stopScan];
VerifyOrReturnError(success, CHIP_ERROR_INTERNAL);

SetCommandExitStatus(CHIP_NO_ERROR);
return CHIP_NO_ERROR;
}

CHIP_ERROR DiscoverCommissionablesListCommand::RunCommand()
{
VerifyOrReturnError(IsInteractive(), CHIP_ERROR_INCORRECT_STATE);

dispatch_sync(gDispatchQueue, ^{
auto resultsCount = [gDiscoveredDevices count];
VerifyOrReturn(resultsCount > 0, ChipLogProgress(chipTool, "No device discovered."));

uint16_t index = 0;
for (id device in gDiscoveredDevices) {
auto serviceName = [device serviceName];
auto vendorId = [device vendorId];
auto productId = [device productId];
auto discriminator = [device discriminator];

NSLog(
@"\t %u %@ - Discriminator: %@ - Vendor: %@ - Product: %@", index, serviceName, discriminator, vendorId, productId);

index++;
}
});

SetCommandExitStatus(CHIP_NO_ERROR);
return CHIP_NO_ERROR;
}
25 changes: 25 additions & 0 deletions examples/darwin-framework-tool/commands/pairing/Commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,30 @@ class PairBleThread : public PairingCommandBridge
PairBleThread() : PairingCommandBridge("ble-thread", PairingMode::Ble, PairingNetworkType::Thread) {}
};

class PairAlreadyDiscoveredByIndex : public PairingCommandBridge
{
public:
PairAlreadyDiscoveredByIndex() :
PairingCommandBridge("by-index", PairingMode::AlreadyDiscoveredByIndex, PairingNetworkType::None)
{}
};

class PairAlreadyDiscoveredByIndexWithWiFi : public PairingCommandBridge
{
public:
PairAlreadyDiscoveredByIndexWithWiFi() :
PairingCommandBridge("by-index-with-wifi", PairingMode::AlreadyDiscoveredByIndex, PairingNetworkType::WiFi)
{}
};

class PairAlreadyDiscoveredByIndexWithThread : public PairingCommandBridge
{
public:
PairAlreadyDiscoveredByIndexWithThread() :
PairingCommandBridge("by-index-with-thread", PairingMode::AlreadyDiscoveredByIndex, PairingNetworkType::Thread)
{}
};

class Unpair : public PairingCommandBridge
{
public:
Expand All @@ -71,6 +95,7 @@ void registerCommandsPairing(Commands & commands)
make_unique<PairCodeThread>(),
make_unique<PairBleWiFi>(),
make_unique<PairBleThread>(),
make_unique<PairAlreadyDiscoveredByIndex>(),
make_unique<Unpair>(),
make_unique<OpenCommissioningWindowCommand>(),
make_unique<PreWarmCommissioningCommand>(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ enum class PairingMode
None,
Code,
Ble,
AlreadyDiscoveredByIndex,
};

enum class PairingNetworkType
Expand Down Expand Up @@ -67,6 +68,10 @@ class PairingCommandBridge : public CHIPCommandBridge
AddArgument("setup-pin-code", 0, 134217727, &mSetupPINCode);
AddArgument("discriminator", 0, 4096, &mDiscriminator);
break;
case PairingMode::AlreadyDiscoveredByIndex:
AddArgument("payload", &mOnboardingPayload);
AddArgument("index", 0, UINT16_MAX, &mIndex);
break;
}

AddArgument("use-device-attestation-delegate", 0, 1, &mUseDeviceAttestationDelegate,
Expand All @@ -82,6 +87,7 @@ class PairingCommandBridge : public CHIPCommandBridge

private:
void PairWithCode(NSError * __autoreleasing * error);
void PairWithIndex(NSError * __autoreleasing * error);
void PairWithPayload(NSError * __autoreleasing * error);
void Unpair();
void SetUpDeviceControllerDelegate();
Expand All @@ -94,6 +100,7 @@ class PairingCommandBridge : public CHIPCommandBridge
chip::NodeId mNodeId;
uint16_t mDiscriminator;
uint32_t mSetupPINCode;
uint16_t mIndex;
char * mOnboardingPayload;
chip::Optional<bool> mUseDeviceAttestationDelegate;
chip::Optional<uint16_t> mDeviceAttestationFailsafeTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
using namespace ::chip;
using namespace ::chip::Controller;

extern NSMutableArray * gDiscoveredDevices;

// A no-op MTRDeviceAttestationDelegate which lets us test (by default, in CI)
// commissioning flows that have such a delegate.
@interface NoOpAttestationDelegate : NSObject <MTRDeviceAttestationDelegate>
Expand Down Expand Up @@ -92,6 +94,9 @@ - (void)deviceAttestationCompletedForController:(MTRDeviceController *)controlle
case PairingMode::Ble:
PairWithCode(&error);
break;
case PairingMode::AlreadyDiscoveredByIndex:
PairWithIndex(&error);
break;
}

if (error != nil) {
Expand All @@ -108,6 +113,29 @@ - (void)deviceAttestationCompletedForController:(MTRDeviceController *)controlle
[commissioner setupCommissioningSessionWithPayload:payload newNodeID:@(mNodeId) error:error];
}

void PairingCommandBridge::PairWithIndex(NSError * __autoreleasing * error)
{
SetUpDeviceControllerDelegate();
MTRDeviceController * commissioner = CurrentCommissioner();

if (mIndex >= [gDiscoveredDevices count]) {
auto errorString = [NSString stringWithFormat:@"Error retrieving discovered device at index %@", @(mIndex)];
*error = [[NSError alloc] initWithDomain:@"PairingDomain"
code:MTRErrorCodeGeneralError
userInfo:@ { NSLocalizedDescriptionKey : NSLocalizedString(errorString, nil) }];
return;
}

NSString * onboardingPayload = [NSString stringWithUTF8String:mOnboardingPayload];
auto * payload = [MTRSetupPayload setupPayloadWithOnboardingPayload:onboardingPayload error:error];
if (payload == nil) {
return;
}

auto discoveredDevice = (MTRCommissionableBrowserResult *) gDiscoveredDevices[mIndex];
[commissioner setupCommissioningSessionWithDiscoveredDevice:discoveredDevice payload:payload newNodeID:@(mNodeId) error:error];
}

void PairingCommandBridge::PairWithPayload(NSError * __autoreleasing * error)
{
NSString * onboardingPayload = [NSString stringWithUTF8String:mOnboardingPayload];
Expand Down
2 changes: 2 additions & 0 deletions examples/darwin-framework-tool/main.mm
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#import "logging/logging.h"

#include "commands/common/Commands.h"
#include "commands/discover/Commands.h"
#include "commands/interactive/Commands.h"
#include "commands/pairing/Commands.h"
#include "commands/payload/Commands.h"
Expand All @@ -37,6 +38,7 @@ int main(int argc, const char * argv[])

Commands commands;
registerCommandsPairing(commands);
registerCommandsDiscover(commands);
registerCommandsInteractive(commands);
registerCommandsPayload(commands);
registerClusterOtaSoftwareUpdateProviderInteractive(commands);
Expand Down
Loading

0 comments on commit 1325997

Please sign in to comment.