diff --git a/examples/chip-tool/BUILD.gn b/examples/chip-tool/BUILD.gn index 97df8a48b5051d..2b99f1cc106a58 100644 --- a/examples/chip-tool/BUILD.gn +++ b/examples/chip-tool/BUILD.gn @@ -59,6 +59,7 @@ static_library("chip-tool-utils") { "commands/common/Commands.cpp", "commands/common/Commands.h", "commands/common/CredentialIssuerCommands.h", + "commands/common/DeviceScanner.cpp", "commands/common/HexConversion.h", "commands/common/RemoteDataModelLogger.cpp", "commands/common/RemoteDataModelLogger.h", diff --git a/examples/chip-tool/commands/common/DeviceScanner.cpp b/examples/chip-tool/commands/common/DeviceScanner.cpp new file mode 100644 index 00000000000000..af3accbbc03b4e --- /dev/null +++ b/examples/chip-tool/commands/common/DeviceScanner.cpp @@ -0,0 +1,120 @@ +/* + * 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 "DeviceScanner.h" + +using namespace chip; +using namespace chip::Ble; +using namespace chip::Dnssd; + +CHIP_ERROR DeviceScanner::Start() +{ + mDiscoveredResults.clear(); + +#if CHIP_TOOL_DEVICE_SCANNER_USE_BLE + ReturnErrorOnFailure(DeviceLayer::PlatformMgrImpl().StartBleScan(this)); +#endif // CHIP_TOOL_DEVICE_SCANNER_USE_BLE + + ReturnErrorOnFailure(mDNSResolver.Init(DeviceLayer::UDPEndPointManager())); + mDNSResolver.SetCommissioningDelegate(this); + + DiscoveryFilter filter(DiscoveryFilterType::kNone, (uint64_t) 0); + return mDNSResolver.DiscoverCommissionableNodes(filter); +} + +CHIP_ERROR DeviceScanner::Stop() +{ +#if CHIP_TOOL_DEVICE_SCANNER_USE_BLE + ReturnErrorOnFailure(DeviceLayer::PlatformMgrImpl().StopBleScan()); +#endif // CHIP_TOOL_DEVICE_SCANNER_USE_BLE + + mDNSResolver.SetCommissioningDelegate(nullptr); + ReturnErrorOnFailure(mDNSResolver.StopDiscovery()); + mDNSResolver.Shutdown(); + return CHIP_NO_ERROR; +} + +void DeviceScanner::OnNodeDiscovered(const DiscoveredNodeData & nodeData) +{ + auto & commissionData = nodeData.commissionData; + + auto discriminator = commissionData.longDiscriminator; + auto vendorId = static_cast(commissionData.vendorId); + auto productId = commissionData.productId; + + ChipLogProgress(chipTool, "OnNodeDiscovered (MDNS): discriminator: %u, vendorId: %u, productId: %u", discriminator, vendorId, + productId); + + auto & resolutionData = nodeData.resolutionData; + for (size_t i = 0; i < resolutionData.numIPs; i++) + { + auto params = Controller::SetUpCodePairerParameters(resolutionData, i); + DeviceScannerResult result = { params, vendorId, productId, discriminator }; + mDiscoveredResults.push_back(result); + } + + nodeData.LogDetail(); +} + +#if CHIP_TOOL_DEVICE_SCANNER_USE_BLE +void DeviceScanner::OnBleScanResult(BLE_CONNECTION_OBJECT connObj, const ChipBLEDeviceIdentificationInfo & info) +{ + auto discriminator = info.GetDeviceDiscriminator(); + auto vendorId = static_cast(info.GetVendorId()); + auto productId = info.GetProductId(); + + ChipLogProgress(chipTool, "OnNodeDiscovered (BLE): discriminator: %u, vendorId: %u, productId: %u", discriminator, vendorId, + productId); + + auto params = Controller::SetUpCodePairerParameters(connObj, false /* connected */); + DeviceScannerResult result = { params, vendorId, productId, discriminator }; + mDiscoveredResults.push_back(result); +} +#endif // CHIP_TOOL_DEVICE_SCANNER_USE_BLE + +CHIP_ERROR DeviceScanner::Get(uint16_t index, RendezvousParameters & params) +{ + VerifyOrReturnError(index < mDiscoveredResults.size(), CHIP_ERROR_NOT_FOUND); + + auto & result = mDiscoveredResults.at(index); + params = result.mParams; + return CHIP_NO_ERROR; +} + +void DeviceScanner::Log() const +{ + auto resultsCount = mDiscoveredResults.size(); + VerifyOrReturn(resultsCount > 0, ChipLogProgress(chipTool, "No device discovered.")); + + uint16_t index = 0; + for (auto & result : mDiscoveredResults) + { + char addr[Transport::PeerAddress::kMaxToStringSize]; + result.mParams.GetPeerAddress().ToString(addr); + + ChipLogProgress(chipTool, "\t %u - Discriminator: %u - Vendor: %u - Product: %u - %s", index, result.mDiscriminator, + result.mVendorId, result.mProductId, addr); + index++; + } +} + +DeviceScanner & GetDeviceScanner() +{ + static DeviceScanner scanner; + return scanner; +} diff --git a/examples/chip-tool/commands/common/DeviceScanner.h b/examples/chip-tool/commands/common/DeviceScanner.h new file mode 100644 index 00000000000000..62479a36edba0f --- /dev/null +++ b/examples/chip-tool/commands/common/DeviceScanner.h @@ -0,0 +1,70 @@ +/* + * 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 + +#include +#include + +#include + +#if CONFIG_NETWORK_LAYER_BLE +#if CHIP_DEVICE_LAYER_TARGET_DARWIN +#include +#define CHIP_TOOL_DEVICE_SCANNER_USE_BLE 1 +#endif // CHIP_DEVICE_LAYER_TARGET_DARWIN +#endif // CONFIG_NETWORK_LAYER_BLE + +#ifndef CHIP_TOOL_DEVICE_SCANNER_USE_BLE +#define CHIP_TOOL_DEVICE_SCANNER_USE_BLE 0 +#endif // CHIP_TOOL_DEVICE_SCANNER_USE_BLE + +struct DeviceScannerResult +{ + chip::Controller::SetUpCodePairerParameters mParams; + chip::VendorId mVendorId; + uint16_t mProductId; + uint16_t mDiscriminator; +}; + +class DeviceScanner : public chip::Dnssd::CommissioningResolveDelegate +#if CHIP_TOOL_DEVICE_SCANNER_USE_BLE + , + public chip::DeviceLayer::BleScannerDelegate +#endif // CHIP_TOOL_DEVICE_SCANNER_USE_BLE +{ +public: + CHIP_ERROR Start(); + CHIP_ERROR Stop(); + CHIP_ERROR Get(uint16_t index, chip::RendezvousParameters & params); + void Log() const; + + /////////// CommissioningResolveDelegate Interface ///////// + void OnNodeDiscovered(const chip::Dnssd::DiscoveredNodeData & nodeData) override; + +#if CHIP_TOOL_DEVICE_SCANNER_USE_BLE + /////////// BleScannerDelegate Interface ///////// + void OnBleScanResult(BLE_CONNECTION_OBJECT connObj, const chip::Ble::ChipBLEDeviceIdentificationInfo & info) override; +#endif // CHIP_TOOL_DEVICE_SCANNER_USE_BLE + +private: + std::vector mDiscoveredResults; + chip::Dnssd::ResolverProxy mDNSResolver; +}; + +DeviceScanner & GetDeviceScanner(); diff --git a/examples/chip-tool/commands/discover/Commands.h b/examples/chip-tool/commands/discover/Commands.h index 5f8049e1081205..e2a2209d2fc83c 100644 --- a/examples/chip-tool/commands/discover/Commands.h +++ b/examples/chip-tool/commands/discover/Commands.h @@ -73,6 +73,9 @@ void registerCommandsDiscover(Commands & commands, CredentialIssuerCommands * cr commands_list clusterCommands = { make_unique(credsIssuerConfig), + make_unique(credsIssuerConfig), + make_unique(credsIssuerConfig), + make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), diff --git a/examples/chip-tool/commands/discover/DiscoverCommissionablesCommand.cpp b/examples/chip-tool/commands/discover/DiscoverCommissionablesCommand.cpp index 035abae0769828..ed5d33aa0ed274 100644 --- a/examples/chip-tool/commands/discover/DiscoverCommissionablesCommand.cpp +++ b/examples/chip-tool/commands/discover/DiscoverCommissionablesCommand.cpp @@ -17,6 +17,7 @@ */ #include "DiscoverCommissionablesCommand.h" +#include #include #include @@ -35,6 +36,33 @@ void DiscoverCommissionablesCommandBase::OnDiscoveredDevice(const chip::Dnssd::D } } +CHIP_ERROR DiscoverCommissionablesStartCommand::RunCommand() +{ + VerifyOrReturnError(IsInteractive(), CHIP_ERROR_INCORRECT_STATE); + ReturnErrorOnFailure(GetDeviceScanner().Start()); + + SetCommandExitStatus(CHIP_NO_ERROR); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiscoverCommissionablesStopCommand::RunCommand() +{ + VerifyOrReturnError(IsInteractive(), CHIP_ERROR_INCORRECT_STATE); + ReturnErrorOnFailure(GetDeviceScanner().Stop()); + + SetCommandExitStatus(CHIP_NO_ERROR); + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiscoverCommissionablesListCommand::RunCommand() +{ + VerifyOrReturnError(IsInteractive(), CHIP_ERROR_INCORRECT_STATE); + GetDeviceScanner().Log(); + + SetCommandExitStatus(CHIP_NO_ERROR); + return CHIP_NO_ERROR; +} + CHIP_ERROR DiscoverCommissionablesCommand::RunCommand() { mCommissioner = &CurrentCommissioner(); diff --git a/examples/chip-tool/commands/discover/DiscoverCommissionablesCommand.h b/examples/chip-tool/commands/discover/DiscoverCommissionablesCommand.h index 74d946cea4cd76..bac24634152823 100644 --- a/examples/chip-tool/commands/discover/DiscoverCommissionablesCommand.h +++ b/examples/chip-tool/commands/discover/DiscoverCommissionablesCommand.h @@ -43,6 +43,36 @@ class DiscoverCommissionablesCommandBase : public CHIPCommand, public chip::Cont chip::Optional mDiscoverOnce; }; +class DiscoverCommissionablesStartCommand : public CHIPCommand +{ +public: + DiscoverCommissionablesStartCommand(CredentialIssuerCommands * credIssuerCommands) : CHIPCommand("start", credIssuerCommands) {} + + /////////// CHIPCommand Interface ///////// + CHIP_ERROR RunCommand() override; + chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(30); } +}; + +class DiscoverCommissionablesStopCommand : public CHIPCommand +{ +public: + DiscoverCommissionablesStopCommand(CredentialIssuerCommands * credIssuerCommands) : CHIPCommand("stop", credIssuerCommands) {} + + /////////// CHIPCommand Interface ///////// + CHIP_ERROR RunCommand() override; + chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(1); } +}; + +class DiscoverCommissionablesListCommand : public CHIPCommand +{ +public: + DiscoverCommissionablesListCommand(CredentialIssuerCommands * credIssuerCommands) : CHIPCommand("list", credIssuerCommands) {} + + /////////// CHIPCommand Interface ///////// + CHIP_ERROR RunCommand() override; + chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(1); } +}; + class DiscoverCommissionablesCommand : public DiscoverCommissionablesCommandBase { public: diff --git a/examples/chip-tool/commands/pairing/Commands.h b/examples/chip-tool/commands/pairing/Commands.h index 4ac57177bf806f..0db8e0c59e2fef 100644 --- a/examples/chip-tool/commands/pairing/Commands.h +++ b/examples/chip-tool/commands/pairing/Commands.h @@ -181,6 +181,24 @@ class PairAlreadyDiscovered : public PairingCommand {} }; +class PairAlreadyDiscoveredByIndex : public PairingCommand +{ +public: + PairAlreadyDiscoveredByIndex(CredentialIssuerCommands * credsIssuerConfig) : + PairingCommand("already-discovered-by-index", PairingMode::AlreadyDiscoveredByIndex, PairingNetworkType::None, + credsIssuerConfig) + {} +}; + +class PairAlreadyDiscoveredByIndexWithWiFi : public PairingCommand +{ +public: + PairAlreadyDiscoveredByIndexWithWiFi(CredentialIssuerCommands * credsIssuerConfig) : + PairingCommand("already-discovered-by-index-with-wifi", PairingMode::AlreadyDiscoveredByIndex, PairingNetworkType::WiFi, + credsIssuerConfig) + {} +}; + class StartUdcServerCommand : public CHIPCommand { public: @@ -208,6 +226,8 @@ void registerCommandsPairing(Commands & commands, CredentialIssuerCommands * cre make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), + make_unique(credsIssuerConfig), + make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), diff --git a/examples/chip-tool/commands/pairing/PairingCommand.cpp b/examples/chip-tool/commands/pairing/PairingCommand.cpp index 5dabeb69837381..ed48fd912f91a3 100644 --- a/examples/chip-tool/commands/pairing/PairingCommand.cpp +++ b/examples/chip-tool/commands/pairing/PairingCommand.cpp @@ -18,6 +18,7 @@ #include "PairingCommand.h" #include "platform/PlatformManager.h" +#include #include #include #include @@ -78,6 +79,9 @@ CHIP_ERROR PairingCommand::RunInternal(NodeId remoteId) case PairingMode::AlreadyDiscovered: err = Pair(remoteId, PeerAddress::UDP(mRemoteAddr.address, mRemotePort, mRemoteAddr.interfaceId)); break; + case PairingMode::AlreadyDiscoveredByIndex: + err = PairWithMdnsOrBleByIndex(remoteId, mIndex); + break; } return err; @@ -167,6 +171,27 @@ CHIP_ERROR PairingCommand::Pair(NodeId remoteId, PeerAddress address) return err; } +CHIP_ERROR PairingCommand::PairWithMdnsOrBleByIndex(NodeId remoteId, uint16_t index) +{ + VerifyOrReturnError(IsInteractive(), CHIP_ERROR_INCORRECT_STATE); + + RendezvousParameters params; + ReturnErrorOnFailure(GetDeviceScanner().Get(index, params)); + params.SetSetupPINCode(mSetupPINCode); + + CHIP_ERROR err = CHIP_NO_ERROR; + if (mPaseOnly.ValueOr(false)) + { + err = CurrentCommissioner().EstablishPASEConnection(remoteId, params); + } + else + { + auto commissioningParams = GetCommissioningParameters(); + err = CurrentCommissioner().PairDevice(remoteId, params, commissioningParams); + } + return err; +} + CHIP_ERROR PairingCommand::PairWithMdns(NodeId remoteId) { Dnssd::DiscoveryFilter filter(mFilterType); diff --git a/examples/chip-tool/commands/pairing/PairingCommand.h b/examples/chip-tool/commands/pairing/PairingCommand.h index 970b4c78587c0d..f12353e010a40c 100644 --- a/examples/chip-tool/commands/pairing/PairingCommand.h +++ b/examples/chip-tool/commands/pairing/PairingCommand.h @@ -35,6 +35,7 @@ enum class PairingMode Ble, SoftAP, AlreadyDiscovered, + AlreadyDiscoveredByIndex, OnNetwork, }; @@ -114,6 +115,12 @@ class PairingCommand : public CHIPCommand, AddArgument("device-remote-port", 0, UINT16_MAX, &mRemotePort); AddArgument("pase-only", 0, 1, &mPaseOnly); break; + case PairingMode::AlreadyDiscoveredByIndex: + AddArgument("skip-commissioning-complete", 0, 1, &mSkipCommissioningComplete); + AddArgument("setup-pin-code", 0, 134217727, &mSetupPINCode); + AddArgument("index", 0, UINT16_MAX, &mIndex); + AddArgument("pase-only", 0, 1, &mPaseOnly); + break; } switch (filterType) @@ -171,6 +178,7 @@ class PairingCommand : public CHIPCommand, CHIP_ERROR PairWithMdns(NodeId remoteId); CHIP_ERROR PairWithCode(NodeId remoteId); CHIP_ERROR PaseWithCode(NodeId remoteId); + CHIP_ERROR PairWithMdnsOrBleByIndex(NodeId remoteId, uint16_t index); CHIP_ERROR Unpair(NodeId remoteId); chip::Controller::CommissioningParameters GetCommissioningParameters(); @@ -189,6 +197,7 @@ class PairingCommand : public CHIPCommand, uint16_t mRemotePort; uint16_t mDiscriminator; uint32_t mSetupPINCode; + uint16_t mIndex; chip::ByteSpan mOperationalDataset; chip::ByteSpan mSSID; chip::ByteSpan mPassword; diff --git a/src/ble/BleConnectionDelegate.h b/src/ble/BleConnectionDelegate.h index 694cb26e5bf36b..d5e10d29a9a597 100644 --- a/src/ble/BleConnectionDelegate.h +++ b/src/ble/BleConnectionDelegate.h @@ -55,6 +55,10 @@ class DLL_EXPORT BleConnectionDelegate // out of a peripheral that matches the given discriminator. virtual void NewConnection(BleLayer * bleLayer, void * appState, const SetupDiscriminator & connDiscriminator) = 0; + // Call this function to delegate the connection steps required to get a connected BLE_CONNECTION_OBJECT + // out of a disconnected BLE_CONNECTION_OBJECT. + virtual void NewConnection(BleLayer * bleLayer, void * appState, BLE_CONNECTION_OBJECT connObj) = 0; + // Call this function to stop the connection virtual CHIP_ERROR CancelConnection() = 0; }; diff --git a/src/ble/BleLayer.cpp b/src/ble/BleLayer.cpp index b560e6dc511592..9109924ccd3754 100644 --- a/src/ble/BleLayer.cpp +++ b/src/ble/BleLayer.cpp @@ -389,6 +389,22 @@ CHIP_ERROR BleLayer::NewBleConnectionByDiscriminator(const SetupDiscriminator & return CHIP_NO_ERROR; } +CHIP_ERROR BleLayer::NewBleConnectionByObject(BLE_CONNECTION_OBJECT connObj, void * appState, + BleConnectionDelegate::OnConnectionCompleteFunct onSuccess, + BleConnectionDelegate::OnConnectionErrorFunct onError) +{ + VerifyOrReturnError(mState == kState_Initialized, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mConnectionDelegate != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mBleTransport != nullptr, CHIP_ERROR_INCORRECT_STATE); + + mConnectionDelegate->OnConnectionComplete = onSuccess; + mConnectionDelegate->OnConnectionError = onError; + + mConnectionDelegate->NewConnection(this, appState == nullptr ? this : appState, connObj); + + return CHIP_NO_ERROR; +} + CHIP_ERROR BleLayer::NewBleConnectionByObject(BLE_CONNECTION_OBJECT connObj) { VerifyOrReturnError(mState == kState_Initialized, CHIP_ERROR_INCORRECT_STATE); diff --git a/src/ble/BleLayer.h b/src/ble/BleLayer.h index 9d57ddee8536e9..1f9dec2860a696 100644 --- a/src/ble/BleLayer.h +++ b/src/ble/BleLayer.h @@ -249,6 +249,9 @@ class DLL_EXPORT BleLayer CHIP_ERROR NewBleConnectionByDiscriminator(const SetupDiscriminator & connDiscriminator, void * appState = nullptr, BleConnectionDelegate::OnConnectionCompleteFunct onSuccess = OnConnectionComplete, BleConnectionDelegate::OnConnectionErrorFunct onError = OnConnectionError); + CHIP_ERROR NewBleConnectionByObject(BLE_CONNECTION_OBJECT connObj, void * appState, + BleConnectionDelegate::OnConnectionCompleteFunct onSuccess = OnConnectionComplete, + BleConnectionDelegate::OnConnectionErrorFunct onError = OnConnectionError); CHIP_ERROR NewBleConnectionByObject(BLE_CONNECTION_OBJECT connObj); CHIP_ERROR NewBleEndPoint(BLEEndPoint ** retEndPoint, BLE_CONNECTION_OBJECT connObj, BleRole role, bool autoClose); diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index e42a13aed4c5fd..cce4684029169e 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -704,6 +704,16 @@ CHIP_ERROR DeviceCommissioner::EstablishPASEConnection(NodeId remoteDeviceId, Re { SuccessOrExit(err = mSystemState->BleLayer()->NewBleConnectionByObject(params.GetConnectionObject())); } + else if (params.HasDiscoveredObject()) + { + // The RendezvousParameters argument needs to be recovered if the search succeed, so save them + // for later. + mRendezvousParametersForDeviceDiscoveredOverBle = params; + SuccessOrExit(err = mSystemState->BleLayer()->NewBleConnectionByObject(params.GetDiscoveredObject(), this, + OnDiscoveredDeviceOverBleSuccess, + OnDiscoveredDeviceOverBleError)); + ExitNow(CHIP_NO_ERROR); + } else if (params.HasDiscriminator()) { // The RendezvousParameters argument needs to be recovered if the search succeed, so save them diff --git a/src/controller/SetUpCodePairer.cpp b/src/controller/SetUpCodePairer.cpp index e630d7630b9fdc..a257fa7d92bf8d 100644 --- a/src/controller/SetUpCodePairer.cpp +++ b/src/controller/SetUpCodePairer.cpp @@ -585,10 +585,18 @@ SetUpCodePairerParameters::SetUpCodePairerParameters(const Dnssd::CommonResoluti } #if CONFIG_NETWORK_LAYER_BLE -SetUpCodePairerParameters::SetUpCodePairerParameters(BLE_CONNECTION_OBJECT connObj) +SetUpCodePairerParameters::SetUpCodePairerParameters(BLE_CONNECTION_OBJECT connObj, bool connected) { Transport::PeerAddress peerAddress = Transport::PeerAddress::BLE(); - SetPeerAddress(peerAddress).SetConnectionObject(connObj); + SetPeerAddress(peerAddress); + if (connected) + { + SetConnectionObject(connObj); + } + else + { + SetDiscoveredObject(connObj); + } } #endif // CONFIG_NETWORK_LAYER_BLE diff --git a/src/controller/SetUpCodePairer.h b/src/controller/SetUpCodePairer.h index 82c6fc33157cb8..1fd1ebffdb903e 100644 --- a/src/controller/SetUpCodePairer.h +++ b/src/controller/SetUpCodePairer.h @@ -53,7 +53,7 @@ class SetUpCodePairerParameters : public RendezvousParameters public: SetUpCodePairerParameters(const Dnssd::CommonResolutionData & data, size_t index); #if CONFIG_NETWORK_LAYER_BLE - SetUpCodePairerParameters(BLE_CONNECTION_OBJECT connObj); + SetUpCodePairerParameters(BLE_CONNECTION_OBJECT connObj, bool connected = true); #endif // CONFIG_NETWORK_LAYER_BLE char mHostName[Dnssd::kHostNameMaxLength + 1] = {}; Inet::InterfaceId mInterfaceId; diff --git a/src/platform/Darwin/BLEManagerImpl.cpp b/src/platform/Darwin/BLEManagerImpl.cpp index 0472f1908d9cbb..712178b49ccfd9 100644 --- a/src/platform/Darwin/BLEManagerImpl.cpp +++ b/src/platform/Darwin/BLEManagerImpl.cpp @@ -88,11 +88,21 @@ void BLEManagerImpl::_Shutdown() } } -CHIP_ERROR BLEManagerImpl::PrepareConnection() +CHIP_ERROR BLEManagerImpl::StartScan(BleScannerDelegate * delegate) { if (mConnectionDelegate) { - static_cast(mConnectionDelegate)->PrepareConnection(); + static_cast(mConnectionDelegate)->StartScan(delegate); + return CHIP_NO_ERROR; + } + return CHIP_ERROR_INCORRECT_STATE; +} + +CHIP_ERROR BLEManagerImpl::StopScan() +{ + if (mConnectionDelegate) + { + static_cast(mConnectionDelegate)->StopScan(); return CHIP_NO_ERROR; } return CHIP_ERROR_INCORRECT_STATE; diff --git a/src/platform/Darwin/BLEManagerImpl.h b/src/platform/Darwin/BLEManagerImpl.h index 9d54d7d01a967f..a1205298f7c1ab 100644 --- a/src/platform/Darwin/BLEManagerImpl.h +++ b/src/platform/Darwin/BLEManagerImpl.h @@ -27,6 +27,9 @@ namespace chip { namespace DeviceLayer { + +class BleScannerDelegate; + namespace Internal { using namespace chip::Ble; @@ -42,7 +45,8 @@ class BLEManagerImpl final : public BLEManager, private BleLayer public: CHIP_ERROR ConfigureBle(uint32_t aNodeId, bool aIsCentral) { return CHIP_NO_ERROR; } - CHIP_ERROR PrepareConnection(); + CHIP_ERROR StartScan(BleScannerDelegate * delegate = nullptr); + CHIP_ERROR StopScan(); private: // ===== Members that implement the BLEManager internal interface. diff --git a/src/platform/Darwin/BleConnectionDelegate.h b/src/platform/Darwin/BleConnectionDelegate.h index 072145e47f466a..a86743720a1497 100644 --- a/src/platform/Darwin/BleConnectionDelegate.h +++ b/src/platform/Darwin/BleConnectionDelegate.h @@ -26,8 +26,10 @@ namespace Internal { class BleConnectionDelegateImpl : public Ble::BleConnectionDelegate { public: - void PrepareConnection(); + void StartScan(BleScannerDelegate * delegate = nullptr); + void StopScan(); virtual void NewConnection(Ble::BleLayer * bleLayer, void * appState, const SetupDiscriminator & connDiscriminator); + virtual void NewConnection(Ble::BleLayer * bleLayer, void * appState, BLE_CONNECTION_OBJECT connObj); virtual CHIP_ERROR CancelConnection(); }; diff --git a/src/platform/Darwin/BleConnectionDelegateImpl.mm b/src/platform/Darwin/BleConnectionDelegateImpl.mm index 69973669318a62..9f05bb65edae16 100644 --- a/src/platform/Darwin/BleConnectionDelegateImpl.mm +++ b/src/platform/Darwin/BleConnectionDelegateImpl.mm @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -40,9 +41,16 @@ using namespace chip::Ble; constexpr uint64_t kScanningWithDiscriminatorTimeoutInSeconds = 60; -constexpr uint64_t kScanningWithoutDiscriminatorTimeoutInSeconds = 120; +constexpr uint64_t kScanningWithoutDelegateTimeoutInSeconds = 120; constexpr const char * kBleWorkQueueName = "org.csa-iot.matter.framework.ble.workqueue"; +typedef NS_ENUM(uint8_t, BleConnectionMode) { + kUndefined = 0, + kScanningWithoutDelegate, + kScanning, + kConnecting, +}; + @interface BleConnection : NSObject @property (strong, nonatomic) dispatch_queue_t chipWorkQueue; @@ -51,23 +59,28 @@ @interface BleConnection : NSObject (timeout * NSEC_PER_SEC)), DISPATCH_TIME_FOREVER, 5 * NSEC_PER_SEC); + if ([self isConnecting]) { + auto timeout = static_cast(kScanningWithDiscriminatorTimeoutInSeconds * NSEC_PER_SEC); + dispatch_source_set_timer(_timer, dispatch_walltime(nullptr, timeout), DISPATCH_TIME_FOREVER, 5 * NSEC_PER_SEC); + } else if ([self isScanningWithoutDelegate]) { + auto timeout = static_cast(kScanningWithoutDelegateTimeoutInSeconds * NSEC_PER_SEC); + dispatch_source_set_timer(_timer, dispatch_walltime(nullptr, timeout), DISPATCH_TIME_FOREVER, 5 * NSEC_PER_SEC); + } else if ([self isScanning]) { + dispatch_source_cancel(_timer); + } else { + // It should not happens. + [self stop]; + [self dispatchConnectionError:CHIP_ERROR_INCORRECT_STATE]; + } } // All our callback dispatch must happen on _chipWorkQueue @@ -258,39 +343,52 @@ - (void)centralManager:(CBCentralManager *)central RSSI:(NSNumber *)RSSI { NSNumber * isConnectable = [advertisementData objectForKey:CBAdvertisementDataIsConnectable]; - if ([isConnectable boolValue]) { - NSDictionary * servicesData = [advertisementData objectForKey:CBAdvertisementDataServiceDataKey]; - for (CBUUID * serviceUUID in servicesData) { - if ([serviceUUID.data isEqualToData:_shortServiceUUID.data]) { - NSData * serviceData = [servicesData objectForKey:serviceUUID]; - - NSUInteger length = [serviceData length]; - if (length == 8) { - const uint8_t * bytes = (const uint8_t *) [serviceData bytes]; - uint8_t opCode = bytes[0]; - uint16_t discriminator = (bytes[1] | (bytes[2] << 8)) & 0xfff; - - if (opCode == 0 || opCode == 1) { - if (![self hasDiscriminator]) { - ChipLogProgress(Ble, "Storing device %p with discriminator: %d", peripheral, discriminator); - _cachedPeripherals[@(discriminator)] = peripheral; - } else if ([self checkDiscriminator:discriminator]) { - ChipLogProgress(Ble, "Connecting to device %p with discriminator: %d", peripheral, discriminator); - [self connect:peripheral]; - [self stopScanning]; - } - } - } + if ([isConnectable boolValue] == NO) { + return; + } - break; - } + NSDictionary * servicesData = [advertisementData objectForKey:CBAdvertisementDataServiceDataKey]; + NSData * serviceData; + for (CBUUID * serviceUUID in servicesData) { + if ([serviceUUID.data isEqualToData:_shortServiceUUID.data]) { + serviceData = [servicesData objectForKey:serviceUUID]; + break; } } -} -- (BOOL)hasDiscriminator -{ - return _hasDeviceDiscriminator; + if (!serviceData || [serviceData length] != 8) { + return; + } + + const uint8_t * bytes = (const uint8_t *) [serviceData bytes]; + uint8_t opCode = bytes[0]; + if (opCode != 0 && opCode != 1) { + return; + } + + uint16_t discriminator = (bytes[1] | (bytes[2] << 8)) & 0xfff; + + if ([self isConnecting] and [self checkDiscriminator:discriminator]) { + ChipLogProgress(Ble, "Connecting to device %p with discriminator: %d", peripheral, discriminator); + [self connect:peripheral]; + [self stopScanning]; + return; + } + + if (![self isConnecting]) { + if ([_cachedPeripherals objectForKey:peripheral] == nil) { + ChipLogProgress(Ble, "Storing device %p with discriminator: %d", peripheral, discriminator); + if (_scannerDelegate) { + dispatch_async(_chipWorkQueue, ^{ + ChipBLEDeviceIdentificationInfo info; + memcpy(&info, bytes, sizeof(info)); + _scannerDelegate->OnBleScanResult((__bridge void *) peripheral, info); + }); + } + } + + _cachedPeripherals[peripheral] = serviceData; + } } - (BOOL)checkDiscriminator:(uint16_t)discriminator @@ -428,12 +526,20 @@ - (void)peripheral:(CBPeripheral *)peripheral - (void)start { dispatch_resume(_timer); - [self startScanning]; + + // If a peripheral has already been found, try to connect to it once BLE starts, + // otherwise start scanning to find the peripheral to connect to. + if (_peripheral != nil) { + [self connect:_peripheral]; + } else { + [self startScanning]; + } } - (void)stop { [self stopScanning]; + _scannerDelegate = nil; [_cachedPeripherals removeAllObjects]; _cachedPeripherals = nil; @@ -486,27 +592,42 @@ - (void)connect:(CBPeripheral *)peripheral [_centralManager connectPeripheral:peripheral options:nil]; } -- (void)update +- (void)updateWithDelegate:(chip::DeviceLayer::BleScannerDelegate *)delegate { [_cachedPeripherals removeAllObjects]; + _scannerDelegate = delegate; + _currentMode = (delegate == nullptr) ? kScanningWithoutDelegate : kScanning; + + if (_currentMode == kScanning) { + for (CBPeripheral * cachedPeripheral in _cachedPeripherals) { + NSData * serviceData = _cachedPeripherals[cachedPeripheral]; + dispatch_async(_chipWorkQueue, ^{ + ChipBLEDeviceIdentificationInfo info; + memcpy(&info, [serviceData bytes], sizeof(info)); + _scannerDelegate->OnBleScanResult((__bridge void *) cachedPeripheral, info); + }); + } + } + [self resetTimer]; } - (void)updateWithDiscriminator:(const chip::SetupDiscriminator &)deviceDiscriminator { _deviceDiscriminator = deviceDiscriminator; - _hasDeviceDiscriminator = true; + _scannerDelegate = nil; + _currentMode = kConnecting; CBPeripheral * peripheral = nil; - if (deviceDiscriminator.IsShortDiscriminator()) { - for (NSNumber * longDiscriminator in _cachedPeripherals) { - if ([self checkDiscriminator:[longDiscriminator unsignedShortValue]]) { - peripheral = _cachedPeripherals[longDiscriminator]; - break; - } + for (CBPeripheral * cachedPeripheral in _cachedPeripherals) { + NSData * serviceData = _cachedPeripherals[cachedPeripheral]; + ChipBLEDeviceIdentificationInfo info; + memcpy(&info, [serviceData bytes], sizeof(info)); + + if ([self checkDiscriminator:info.GetDeviceDiscriminator()]) { + peripheral = cachedPeripheral; + break; } - } else { - peripheral = _cachedPeripherals[@(deviceDiscriminator.GetLongValue())]; } if (peripheral) { @@ -518,6 +639,16 @@ - (void)updateWithDiscriminator:(const chip::SetupDiscriminator &)deviceDiscrimi } } +- (void)updateWithPeripheral:(CBPeripheral *)peripheral +{ + _scannerDelegate = nil; + _currentMode = kConnecting; + + ChipLogProgress(Ble, "Connecting to device: %p", peripheral); + [self connect:peripheral]; + [self stopScanning]; +} + /** * private static method to copy service and characteristic UUIDs from CBCharacteristic to a pair of ChipBleUUID objects. * this is used in calls into Chip layer to decouple it from CoreBluetooth diff --git a/src/platform/Darwin/BleScannerDelegate.h b/src/platform/Darwin/BleScannerDelegate.h new file mode 100644 index 00000000000000..bfb0c389179648 --- /dev/null +++ b/src/platform/Darwin/BleScannerDelegate.h @@ -0,0 +1,37 @@ +/* + * + * 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 + +#include +#include + +namespace chip { +namespace DeviceLayer { + +class DLL_EXPORT BleScannerDelegate +{ +public: + virtual ~BleScannerDelegate() {} + + // Called when a scan result is available. + virtual void OnBleScanResult(BLE_CONNECTION_OBJECT connObj, const Ble::ChipBLEDeviceIdentificationInfo & info) = 0; +}; + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/Darwin/PlatformManagerImpl.cpp b/src/platform/Darwin/PlatformManagerImpl.cpp index 656f5d13ccc942..6e78a8195b004f 100644 --- a/src/platform/Darwin/PlatformManagerImpl.cpp +++ b/src/platform/Darwin/PlatformManagerImpl.cpp @@ -161,13 +161,28 @@ bool PlatformManagerImpl::_IsChipStackLockedByCurrentThread() const }; #endif +CHIP_ERROR PlatformManagerImpl::StartBleScan(BleScannerDelegate * delegate) +{ +#if CONFIG_NETWORK_LAYER_BLE + ReturnErrorOnFailure(Internal::BLEMgrImpl().StartScan(delegate)); +#endif // CONFIG_NETWORK_LAYER_BLE + return CHIP_NO_ERROR; +} + +CHIP_ERROR PlatformManagerImpl::StopBleScan() +{ +#if CONFIG_NETWORK_LAYER_BLE + ReturnErrorOnFailure(Internal::BLEMgrImpl().StopScan()); +#endif // CONFIG_NETWORK_LAYER_BLE + return CHIP_NO_ERROR; +} + CHIP_ERROR PlatformManagerImpl::PrepareCommissioning() { - auto error = CHIP_NO_ERROR; #if CONFIG_NETWORK_LAYER_BLE - error = Internal::BLEMgrImpl().PrepareConnection(); + ReturnErrorOnFailure(Internal::BLEMgrImpl().StartScan()); #endif // CONFIG_NETWORK_LAYER_BLE - return error; + return CHIP_NO_ERROR; } } // namespace DeviceLayer diff --git a/src/platform/Darwin/PlatformManagerImpl.h b/src/platform/Darwin/PlatformManagerImpl.h index c40f74e05d437c..a0aff2ab21e439 100644 --- a/src/platform/Darwin/PlatformManagerImpl.h +++ b/src/platform/Darwin/PlatformManagerImpl.h @@ -31,6 +31,8 @@ static constexpr const char * const CHIP_CONTROLLER_QUEUE = "org.csa-iot.matter. namespace chip { namespace DeviceLayer { +class BleScannerDelegate; + /** * Concrete implementation of the PlatformManager singleton object for Darwin platforms. */ @@ -54,6 +56,8 @@ class PlatformManagerImpl final : public PlatformManager, public Internal::Gener return mWorkQueue; } + CHIP_ERROR StartBleScan(BleScannerDelegate * delegate = nullptr); + CHIP_ERROR StopBleScan(); CHIP_ERROR PrepareCommissioning(); System::Clock::Timestamp GetStartTime() { return mStartTime; } diff --git a/src/platform/Linux/BLEManagerImpl.h b/src/platform/Linux/BLEManagerImpl.h index ef7cb53ede7a50..319b4b3468e0ff 100644 --- a/src/platform/Linux/BLEManagerImpl.h +++ b/src/platform/Linux/BLEManagerImpl.h @@ -150,6 +150,7 @@ class BLEManagerImpl final : public BLEManager, // ===== Members that implement virtual methods on BleConnectionDelegate. void NewConnection(BleLayer * bleLayer, void * appState, const SetupDiscriminator & connDiscriminator) override; + void NewConnection(BleLayer * bleLayer, void * appState, BLE_CONNECTION_OBJECT connObj) override{}; CHIP_ERROR CancelConnection() override; // ===== Members that implement virtual methods on ChipDeviceScannerDelegate diff --git a/src/platform/Tizen/BLEManagerImpl.h b/src/platform/Tizen/BLEManagerImpl.h index a685a85205de65..9610d387ee39c8 100644 --- a/src/platform/Tizen/BLEManagerImpl.h +++ b/src/platform/Tizen/BLEManagerImpl.h @@ -134,6 +134,7 @@ class BLEManagerImpl final : public BLEManager, // ===== Members that implement virtual methods on BleConnectionDelegate. void NewConnection(BleLayer * bleLayer, void * appState, const SetupDiscriminator & connDiscriminator) override; + void NewConnection(BleLayer * bleLayer, void * appState, BLE_CONNECTION_OBJECT connObj) override{}; CHIP_ERROR CancelConnection() override; // ===== Members that implement virtual methods on ChipDeviceScannerDelegate diff --git a/src/platform/android/BLEManagerImpl.h b/src/platform/android/BLEManagerImpl.h index 361129cdd42bbe..4d6a6bf94613e9 100644 --- a/src/platform/android/BLEManagerImpl.h +++ b/src/platform/android/BLEManagerImpl.h @@ -91,6 +91,7 @@ class BLEManagerImpl final : public BLEManager, // ===== Members that implement virtual methods on BleConnectionDelegate. void NewConnection(BleLayer * bleLayer, void * appState, const SetupDiscriminator & connDiscriminator) override; + void NewConnection(BleLayer * bleLayer, void * appState, BLE_CONNECTION_OBJECT connObj) override{}; CHIP_ERROR CancelConnection() override; // ===== Members for internal use by the following friends. diff --git a/src/platform/webos/BLEManagerImpl.h b/src/platform/webos/BLEManagerImpl.h index 2ab9a5844e4fdc..eb26e9d498819a 100644 --- a/src/platform/webos/BLEManagerImpl.h +++ b/src/platform/webos/BLEManagerImpl.h @@ -132,6 +132,7 @@ class BLEManagerImpl final : public BLEManager, // ===== Members that implement virtual methods on BleConnectionDelegate. void NewConnection(BleLayer * bleLayer, void * appState, const SetupDiscriminator & connDiscriminator) override; + void NewConnection(BleLayer * bleLayer, void * appState, BLE_CONNECTION_OBJECT connObj) override{}; CHIP_ERROR CancelConnection() override; // ===== Members that implement virtual methods on ChipDeviceScannerDelegate diff --git a/src/protocols/secure_channel/RendezvousParameters.h b/src/protocols/secure_channel/RendezvousParameters.h index ddc1281dd9d0e8..ad0721e232d864 100644 --- a/src/protocols/secure_channel/RendezvousParameters.h +++ b/src/protocols/secure_channel/RendezvousParameters.h @@ -93,8 +93,17 @@ class RendezvousParameters mConnectionObject = connObj; return *this; } + + bool HasDiscoveredObject() const { return mDiscoveredObject != BLE_CONNECTION_UNINITIALIZED; } + BLE_CONNECTION_OBJECT GetDiscoveredObject() const { return mDiscoveredObject; } + RendezvousParameters & SetDiscoveredObject(BLE_CONNECTION_OBJECT connObj) + { + mDiscoveredObject = connObj; + return *this; + } #else bool HasConnectionObject() const { return false; } + bool HasDiscoveredObject() const { return false; } #endif // CONFIG_NETWORK_LAYER_BLE bool HasMRPConfig() const { return mMRPConfig.HasValue(); } @@ -132,6 +141,7 @@ class RendezvousParameters #if CONFIG_NETWORK_LAYER_BLE Ble::BleLayer * mBleLayer = nullptr; BLE_CONNECTION_OBJECT mConnectionObject = BLE_CONNECTION_UNINITIALIZED; + BLE_CONNECTION_OBJECT mDiscoveredObject = BLE_CONNECTION_UNINITIALIZED; #endif // CONFIG_NETWORK_LAYER_BLE };