Skip to content

Commit

Permalink
add ScanNetworks step to CHIPDeviceController (#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 (#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 woody-apple committed Aug 2, 2022
1 parent 3a3fa93 commit 955cef3
Show file tree
Hide file tree
Showing 13 changed files with 678 additions and 14 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 @@ -1592,6 +1592,7 @@ void DeviceCommissioner::CommissioningStageComplete(CHIP_ERROR err, Commissionin
{
mPairingDelegate->OnCommissioningStatusUpdate(PeerId(GetCompressedFabricId(), nodeId), mCommissioningStage, err);
}

if (mCommissioningDelegate == nullptr)
{
return;
Expand Down Expand Up @@ -1747,20 +1748,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 @@ -1809,6 +1817,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 @@ -1847,6 +1861,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 @@ -1976,6 +2023,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 @@ -773,8 +773,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 955cef3

Please sign in to comment.