Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add ScanNetworks step to CHIPDeviceController #20766

Merged
merged 30 commits into from
Jul 28, 2022
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
36bb9b3
DRAFT: add ScanNetworks step to CHIPDeviceController
chrisdecenzo Jul 14, 2022
0aec701
Add android hooks and callbacks for network scan
chrisdecenzo Jul 15, 2022
2ec5b41
Add controller parameters for failsafe timeout, and scans
chrisdecenzo Jul 15, 2022
f01e003
Add callback for ReadCommissioningInfo
chrisdecenzo Jul 15, 2022
9e9a142
straggler file
chrisdecenzo Jul 15, 2022
bd09776
address comments
chrisdecenzo Jul 15, 2022
1b263df
fix android build
chrisdecenzo Jul 15, 2022
0a982eb
DRAFT: add ScanNetworks step to CHIPDeviceController
chrisdecenzo Jul 14, 2022
bfcb784
Add android hooks and callbacks for network scan
chrisdecenzo Jul 15, 2022
cfd3351
Add controller parameters for failsafe timeout, and scans
chrisdecenzo Jul 15, 2022
4bcd7c4
Add callback for ReadCommissioningInfo
chrisdecenzo Jul 15, 2022
756ac8f
straggler file
chrisdecenzo Jul 15, 2022
ac0327f
address comments
chrisdecenzo Jul 15, 2022
b7b58b3
fix android build
chrisdecenzo Jul 15, 2022
4a4b93b
Restyle DRAFT: add ScanNetworks step to CHIPDeviceController (#20808)
restyled-io[bot] Jul 16, 2022
d61ae0d
fix CI
chrisdecenzo Jul 18, 2022
406e727
merge with latest, fix conflicts
chrisdecenzo Jul 18, 2022
2452d0f
fix kotlin build issue
chrisdecenzo Jul 18, 2022
946d0f0
fix java method signature lookup
chrisdecenzo Jul 18, 2022
f06a4f2
fix cirq tests, add name for ScanNetworks step
chrisdecenzo Jul 19, 2022
f1b5c64
attempt to fix cirq tests
chrisdecenzo Jul 20, 2022
3ae3de4
Address comments
chrisdecenzo Jul 26, 2022
8776a7e
Address comments
chrisdecenzo Jul 26, 2022
2282310
sync to master
chrisdecenzo Jul 26, 2022
f158c8e
fix stragglers, restyle
chrisdecenzo Jul 26, 2022
2a5e0a3
address feedback
chrisdecenzo Jul 28, 2022
90cf820
address feedback
chrisdecenzo Jul 28, 2022
16a7ecc
fix build
chrisdecenzo Jul 28, 2022
390b792
fix build
chrisdecenzo Jul 28, 2022
5083311
fix build
chrisdecenzo Jul 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
}

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();
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved

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 = %" PRIu32,
path.mEndpointId);
info.network.wifi.endpoint = path.mEndpointId;
}
else if (features.Has(
app::Clusters::NetworkCommissioning::NetworkCommissioningFeature::kThreadNetworkInterface))
{
ChipLogProgress(Controller, "----- NetworkCommissioning Features: has Thread. endpointid = %" PRIu32,
path.mEndpointId);
info.network.thread.endpoint = path.mEndpointId;
}
else if (features.Has(
app::Clusters::NetworkCommissioning::NetworkCommissioningFeature::kEthernetNetworkInterface))
{
ChipLogProgress(Controller, "----- NetworkCommissioning Features: has Ethernet. endpointid = %" PRIu32,
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(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