Skip to content

Commit

Permalink
add ScanNetworks step to CHIPDeviceController (project-chip#20766)
Browse files Browse the repository at this point in the history
* DRAFT: add ScanNetworks step to CHIPDeviceController

* Add android hooks and callbacks for network scan

* Add controller parameters for failsafe timeout, and scans

* Add callback for ReadCommissioningInfo

* straggler file

* address comments

* fix android build

* DRAFT: add ScanNetworks step to CHIPDeviceController

* Add android hooks and callbacks for network scan

* Add controller parameters for failsafe timeout, and scans

* Add callback for ReadCommissioningInfo

* straggler file

* address comments

* fix android build

* Restyle DRAFT: add ScanNetworks step to CHIPDeviceController (project-chip#20808)

* Restyled by whitespace

* Restyled by google-java-format

Co-authored-by: Restyled.io <[email protected]>

* fix CI

* fix kotlin build issue

* fix java method signature lookup

* fix cirq tests, add name for ScanNetworks step

* attempt to fix cirq tests

* Address comments

* Address comments

* fix stragglers, restyle

* address feedback

* address feedback

* fix build

* fix build

* fix build

Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com>
Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
3 people authored and isiu-apple committed Sep 16, 2022
1 parent f9c5a24 commit 2c60b68
Show file tree
Hide file tree
Showing 13 changed files with 661 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ open class GenericChipDeviceListener : ChipDeviceController.CompletionListener {
// No op
}

override fun onReadCommissioningInfo(vendorId: Int,productId: Int, wifiEndpointId: Int, threadEndpointId: Int) {
// No op
}

override fun onCommissioningStatusUpdate(nodeId: Long, stage: String, errorCode: Int) {
// No op
}

override fun onNotifyChipConnectionClosed() {
// No op
}
Expand Down
86 changes: 83 additions & 3 deletions src/controller/AutoCommissioner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ void AutoCommissioner::SetOperationalCredentialsDelegate(OperationalCredentialsD
CHIP_ERROR AutoCommissioner::SetCommissioningParameters(const CommissioningParameters & params)
{
mParams = params;
if (params.GetFailsafeTimerSeconds().HasValue())
{
ChipLogProgress(Controller, "Setting failsafe timer from parameters");
mParams.SetFailsafeTimerSeconds(params.GetFailsafeTimerSeconds().Value());
}

if (params.GetThreadOperationalDataset().HasValue())
{
ByteSpan dataset = params.GetThreadOperationalDataset().Value();
Expand All @@ -57,6 +63,13 @@ CHIP_ERROR AutoCommissioner::SetCommissioningParameters(const CommissioningParam
ChipLogProgress(Controller, "Setting thread operational dataset from parameters");
mParams.SetThreadOperationalDataset(ByteSpan(mThreadOperationalDataset, dataset.size()));
}

if (params.GetAttemptThreadNetworkScan().HasValue())
{
ChipLogProgress(Controller, "Setting attempt thread scan from parameters");
mParams.SetAttemptThreadNetworkScan(params.GetAttemptThreadNetworkScan().Value());
}

if (params.GetWiFiCredentials().HasValue())
{
WiFiCredentials creds = params.GetWiFiCredentials().Value();
Expand All @@ -73,6 +86,12 @@ CHIP_ERROR AutoCommissioner::SetCommissioningParameters(const CommissioningParam
WiFiCredentials(ByteSpan(mSsid, creds.ssid.size()), ByteSpan(mCredentials, creds.credentials.size())));
}

if (params.GetAttemptWiFiNetworkScan().HasValue())
{
ChipLogProgress(Controller, "Setting attempt wifi scan from parameters");
mParams.SetAttemptWiFiNetworkScan(params.GetAttemptWiFiNetworkScan().Value());
}

if (params.GetCountryCode().HasValue())
{
auto & code = params.GetCountryCode().Value();
Expand Down Expand Up @@ -159,6 +178,25 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(Commissio
}
return CommissioningStage::kArmFailsafe;
case CommissioningStage::kArmFailsafe:
if (mNeedsNetworkSetup)
{
// if there is a WiFi or a Thread endpoint, then perform scan
if ((mParams.GetAttemptWiFiNetworkScan().ValueOr(false) &&
mDeviceCommissioningInfo.network.wifi.endpoint != kInvalidEndpointId) ||
(mParams.GetAttemptThreadNetworkScan().ValueOr(false) &&
mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId))
{
return CommissioningStage::kScanNetworks;
}
ChipLogProgress(Controller, "No NetworkScan enabled or WiFi/Thread endpoint not specified, skipping ScanNetworks");
}
else
{
ChipLogProgress(Controller, "Not a BLE connection, skipping ScanNetworks");
}
// skip scan step
return CommissioningStage::kConfigRegulatory;
case CommissioningStage::kScanNetworks:
return CommissioningStage::kConfigRegulatory;
case CommissioningStage::kConfigRegulatory:
return CommissioningStage::kSendPAICertificateRequest;
Expand Down Expand Up @@ -490,26 +528,68 @@ CHIP_ERROR AutoCommissioner::CommissioningStepFinished(CHIP_ERROR err, Commissio
{
completionStatus.err = err;
}
mParams.SetCompletionStatus(completionStatus);

if (mCommissioningPaused)
{
mPausedStage = nextStage;

if (GetDeviceProxyForStep(nextStage) == nullptr)
{
ChipLogError(Controller, "Invalid device for commissioning");
return CHIP_ERROR_INCORRECT_STATE;
}
return CHIP_NO_ERROR;
}
return PerformStep(nextStage);
}

DeviceProxy * proxy = mCommissioneeDeviceProxy;
DeviceProxy * AutoCommissioner::GetDeviceProxyForStep(CommissioningStage nextStage)
{
if (nextStage == CommissioningStage::kSendComplete ||
(nextStage == CommissioningStage::kCleanup && mOperationalDeviceProxy != nullptr))
{
proxy = mOperationalDeviceProxy;
return mOperationalDeviceProxy;
}
return mCommissioneeDeviceProxy;
}

CHIP_ERROR AutoCommissioner::PerformStep(CommissioningStage nextStage)
{
DeviceProxy * proxy = GetDeviceProxyForStep(nextStage);
if (proxy == nullptr)
{
ChipLogError(Controller, "Invalid device for commissioning");
return CHIP_ERROR_INCORRECT_STATE;
}

mParams.SetCompletionStatus(completionStatus);
mCommissioner->PerformCommissioningStep(proxy, nextStage, mParams, this, GetEndpoint(nextStage),
GetCommandTimeout(proxy, nextStage));
return CHIP_NO_ERROR;
}

void AutoCommissioner::PauseCommissioning()
{
mCommissioningPaused = true;
}

CHIP_ERROR AutoCommissioner::ResumeCommissioning()
{
VerifyOrReturnError(mCommissioningPaused, CHIP_ERROR_INCORRECT_STATE);
mCommissioningPaused = false;

// if no new step was attempted
if (mPausedStage == CommissioningStage::kError)
{
return CHIP_NO_ERROR;
}

CommissioningStage nextStage = mPausedStage;
mPausedStage = CommissioningStage::kError;

return PerformStep(nextStage);
}

void AutoCommissioner::ReleaseDAC()
{
if (mDAC != nullptr)
Expand Down
24 changes: 24 additions & 0 deletions src/controller/AutoCommissioner.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,32 @@ class AutoCommissioner : public CommissioningDelegate

CHIP_ERROR CommissioningStepFinished(CHIP_ERROR err, CommissioningDelegate::CommissioningReport report) override;

/**
* @brief
* This function puts the AutoCommissioner in a paused state to prevent advancing to the next stage.
* It is expected that a DevicePairingDelegate may call this method when processing the
* OnCommissioningStatusUpdate, for example, in order to obtain network credentials from the user based
* upon the results of the NetworkScan.
* Use ResumeCommissioning to continue the commissioning process.
*
*/
void PauseCommissioning();

/**
* @brief
* An error return value means resume failed, for example:
* - AutoCommissioner was not in a paused state.
* - AutoCommissioner was unable to continue (no DeviceProxy)
*/
CHIP_ERROR ResumeCommissioning();

protected:
CommissioningStage GetNextCommissioningStage(CommissioningStage currentStage, CHIP_ERROR & lastErr);
DeviceCommissioner * GetCommissioner() { return mCommissioner; }
CHIP_ERROR PerformStep(CommissioningStage nextStage);

private:
DeviceProxy * GetDeviceProxyForStep(CommissioningStage nextStage);
void ReleaseDAC();
void ReleasePAI();

Expand Down Expand Up @@ -75,6 +96,9 @@ class AutoCommissioner : public CommissioningDelegate
bool mNeedsNetworkSetup = false;
ReadCommissioningInfo mDeviceCommissioningInfo;

CommissioningStage mPausedStage = CommissioningStage::kError;
bool mCommissioningPaused = false;

// TODO: Why were the nonces statically allocated, but the certs dynamically allocated?
uint8_t * mDAC = nullptr;
uint16_t mDACLen = 0;
Expand Down
57 changes: 57 additions & 0 deletions src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1556,6 +1556,7 @@ void DeviceCommissioner::CommissioningStageComplete(CHIP_ERROR err, Commissionin
{
mPairingDelegate->OnCommissioningStatusUpdate(PeerId(GetCompressedFabricId(), nodeId), mCommissioningStage, err);
}

if (mCommissioningDelegate == nullptr)
{
return;
Expand Down Expand Up @@ -1711,20 +1712,27 @@ void DeviceCommissioner::OnDone(app::ReadClient *)
{
if (features.Has(app::Clusters::NetworkCommissioning::NetworkCommissioningFeature::kWiFiNetworkInterface))
{
ChipLogProgress(Controller, "----- NetworkCommissioning Features: has WiFi. endpointid = %u",
path.mEndpointId);
info.network.wifi.endpoint = path.mEndpointId;
}
else if (features.Has(
app::Clusters::NetworkCommissioning::NetworkCommissioningFeature::kThreadNetworkInterface))
{
ChipLogProgress(Controller, "----- NetworkCommissioning Features: has Thread. endpointid = %u",
path.mEndpointId);
info.network.thread.endpoint = path.mEndpointId;
}
else if (features.Has(
app::Clusters::NetworkCommissioning::NetworkCommissioningFeature::kEthernetNetworkInterface))
{
ChipLogProgress(Controller, "----- NetworkCommissioning Features: has Ethernet. endpointid = %u",
path.mEndpointId);
info.network.eth.endpoint = path.mEndpointId;
}
else
{
ChipLogProgress(Controller, "----- NetworkCommissioning Features: no features.");
// TODO: Gross workaround for the empty feature map on all clusters. Remove.
if (info.network.thread.endpoint == kInvalidEndpointId)
{
Expand Down Expand Up @@ -1773,6 +1781,12 @@ void DeviceCommissioner::OnDone(app::ReadClient *)
}
mAttributeCache = nullptr;
mReadClient = nullptr;

if (mPairingDelegate != nullptr)
{
mPairingDelegate->OnReadCommissioningInfo(info);
}

CommissioningDelegate::CommissioningReport report;
report.Set<ReadCommissioningInfo>(info);
CommissioningStageComplete(return_err, report);
Expand Down Expand Up @@ -1811,6 +1825,39 @@ void DeviceCommissioner::OnSetRegulatoryConfigResponse(
commissioner->CommissioningStageComplete(err, report);
}

void DeviceCommissioner::OnScanNetworksFailure(void * context, CHIP_ERROR error)
{
ChipLogProgress(Controller, "Received ScanNetworks failure response %" CHIP_ERROR_FORMAT, error.Format());

DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
if (commissioner->GetPairingDelegate() != nullptr)
{
commissioner->GetPairingDelegate()->OnScanNetworksFailure(error);
}
// need to advance to next step
// clear error so that we don't abort the commissioning when ScanNetworks fails
commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
}

void DeviceCommissioner::OnScanNetworksResponse(void * context,
const NetworkCommissioning::Commands::ScanNetworksResponse::DecodableType & data)
{
CommissioningDelegate::CommissioningReport report;

ChipLogProgress(Controller, "Received ScanNetwork response, networkingStatus=%u debugText=%s",
to_underlying(data.networkingStatus),
(data.debugText.HasValue() ? std::string(data.debugText.Value().data(), data.debugText.Value().size()).c_str()
: "none provided"));
DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);

if (commissioner->GetPairingDelegate() != nullptr)
{
commissioner->GetPairingDelegate()->OnScanNetworksSuccess(data);
}
// need to advance to next step
commissioner->CommissioningStageComplete(CHIP_NO_ERROR);
}

void DeviceCommissioner::OnNetworkConfigResponse(void * context,
const NetworkCommissioning::Commands::NetworkConfigResponse::DecodableType & data)
{
Expand Down Expand Up @@ -1940,6 +1987,16 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio
mReadClient = std::move(readClient);
}
break;
case CommissioningStage::kScanNetworks: {
NetworkCommissioning::Commands::ScanNetworks::Type request;
if (params.GetWiFiCredentials().HasValue())
{
request.ssid.Emplace(params.GetWiFiCredentials().Value().ssid);
}
request.breadcrumb.Emplace(breadcrumb);
SendCommand<NetworkCommissioningCluster>(proxy, request, OnScanNetworksResponse, OnScanNetworksFailure, endpoint, timeout);
break;
}
case CommissioningStage::kConfigRegulatory: {
// To set during config phase:
// UTC time
Expand Down
6 changes: 5 additions & 1 deletion src/controller/CHIPDeviceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -761,8 +761,12 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
void * context,
const chip::app::Clusters::GeneralCommissioning::Commands::SetRegulatoryConfigResponse::DecodableType & data);
static void
OnScanNetworksResponse(void * context,
const app::Clusters::NetworkCommissioning::Commands::ScanNetworksResponse::DecodableType & data);
static void OnScanNetworksFailure(void * context, CHIP_ERROR err);
static void
OnNetworkConfigResponse(void * context,
const chip::app::Clusters::NetworkCommissioning::Commands::NetworkConfigResponse::DecodableType & data);
const app::Clusters::NetworkCommissioning::Commands::NetworkConfigResponse::DecodableType & data);
static void OnConnectNetworkResponse(
void * context, const chip::app::Clusters::NetworkCommissioning::Commands::ConnectNetworkResponse::DecodableType & data);
static void OnCommissioningCompleteResponse(
Expand Down
4 changes: 4 additions & 0 deletions src/controller/CommissioningDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ const char * StageToString(CommissioningStage stage)
return "ArmFailSafe";
break;

case kScanNetworks:
return "ScanNetworks";
break;

case kConfigRegulatory:
return "ConfigRegulatory";
break;
Expand Down
27 changes: 27 additions & 0 deletions src/controller/CommissioningDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ enum CommissioningStage : uint8_t
kFindOperational,
kSendComplete,
kCleanup,
// ScanNetworks can happen anytime after kArmFailsafe.
// However, the circ tests fail if it is earlier in the list
kScanNetworks,
};

const char * StageToString(CommissioningStage stage);
Expand Down Expand Up @@ -261,10 +264,12 @@ class CommissioningParameters
return *this;
}

// If a ThreadOperationalDataset is provided, then the ThreadNetworkScan will not be attempted
CommissioningParameters & SetThreadOperationalDataset(ByteSpan threadOperationalDataset)
{

mThreadOperationalDataset.SetValue(threadOperationalDataset);
mAttemptThreadNetworkScan = MakeOptional(static_cast<bool>(false));
return *this;
}
// This parameter should be set with the information returned from kSendOpCertSigningRequest. It must be set before calling
Expand Down Expand Up @@ -352,6 +357,26 @@ class CommissioningParameters

Credentials::DeviceAttestationDelegate * GetDeviceAttestationDelegate() const { return mDeviceAttestationDelegate; }

// If an SSID is provided, and AttemptWiFiNetworkScan is true,
// then a directed scan will be performed using the SSID provided in the WiFiCredentials object
Optional<bool> GetAttemptWiFiNetworkScan() const { return mAttemptWiFiNetworkScan; }
CommissioningParameters & SetAttemptWiFiNetworkScan(bool attemptWiFiNetworkScan)
{
mAttemptWiFiNetworkScan = MakeOptional(attemptWiFiNetworkScan);
return *this;
}

// If a ThreadOperationalDataset is provided, then the ThreadNetworkScan will not be attempted
Optional<bool> GetAttemptThreadNetworkScan() const { return mAttemptThreadNetworkScan; }
CommissioningParameters & SetAttemptThreadNetworkScan(bool attemptThreadNetworkScan)
{
if (!mThreadOperationalDataset.HasValue())
{
mAttemptThreadNetworkScan = MakeOptional(attemptThreadNetworkScan);
}
return *this;
}

private:
// Items that can be set by the commissioner
Optional<uint16_t> mFailsafeTimerSeconds;
Expand Down Expand Up @@ -379,6 +404,8 @@ class CommissioningParameters
CompletionStatus completionStatus;
Credentials::DeviceAttestationDelegate * mDeviceAttestationDelegate =
nullptr; // Delegate to handle device attestation failures during commissioning
Optional<bool> mAttemptWiFiNetworkScan;
Optional<bool> mAttemptThreadNetworkScan; // This automatically gets set to false when a ThreadOperationalDataset is set
};

struct RequestedCertificate
Expand Down
Loading

0 comments on commit 2c60b68

Please sign in to comment.