Skip to content

Commit

Permalink
Enable Terms and Conditions (TC) feature for AutoCommissioner
Browse files Browse the repository at this point in the history
This commit enables the Terms and Conditions (TC) feature in the
all-clusters-app example application. The changes ensure that the app
can handle TC acknowledgements and enforce required terms and conditions
during the commissioning process.

Changes include:
- Added TC attributes and commands in the General Commissioning cluster.
- Enabled the TC feature in the application configuration.

This enables the TC feature logic in the example app, building on the
initial implementation.
  • Loading branch information
swan-amazon committed Aug 8, 2024
1 parent ba88272 commit bba6401
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2172,6 +2172,22 @@
"source": "server",
"isIncoming": 0,
"isEnabled": 1
},
{
"name": "SetTCAcknowledgements",
"code": 6,
"mfgCode": null,
"source": "client",
"isIncoming": 1,
"isEnabled": 1
},
{
"name": "SetTCAcknowledgementsResponse",
"code": 7,
"mfgCode": null,
"source": "server",
"isIncoming": 0,
"isEnabled": 1
}
],
"attributes": [
Expand Down Expand Up @@ -2255,6 +2271,70 @@
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "TCAcceptedVersion",
"code": 5,
"mfgCode": null,
"side": "server",
"type": "int16u",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "TCMinRequiredVersion",
"code": 6,
"mfgCode": null,
"side": "server",
"type": "int16u",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "TCAcknowledgements",
"code": 7,
"mfgCode": null,
"side": "server",
"type": "bitmap16",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0x0000",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "TCAcknowledgementsRequired",
"code": 8,
"mfgCode": null,
"side": "server",
"type": "boolean",
"included": 1,
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "GeneratedCommandList",
"code": 65528,
Expand Down Expand Up @@ -2329,7 +2409,7 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"defaultValue": "1",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
Expand Down
18 changes: 17 additions & 1 deletion examples/chip-tool/commands/pairing/PairingCommand.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2020-2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -129,6 +129,22 @@ CommissioningParameters PairingCommand::GetCommissioningParameters()
params.SetCountryCode(CharSpan::fromCharString(mCountryCode.Value()));
}

if (mRequireTCAcknowledgements.HasValue())
{
params.SetRequireTermsAndConditionsAcknowledgement(mRequireTCAcknowledgements.Value());
}

// mTCAcknowledgements and mTCAcknowledgementVersion are optional, but related. When one is missing, default the value to 0, to
// increase the test tools ability to test the applications.
if (mTCAcknowledgements.HasValue() || mTCAcknowledgementVersion.HasValue())
{
TermsAndConditionsAcknowledgement termsAndConditionsAcknowledgement = {
.acceptedTermsAndConditions = mTCAcknowledgements.ValueOr(0),
.acceptedTermsAndConditionsVersion = mTCAcknowledgementVersion.ValueOr(0),
};
params.SetTermsAndConditionsAcknowledgement(termsAndConditionsAcknowledgement);
}

// mTimeZoneList is an optional argument managed by TypedComplexArgument mComplex_TimeZones.
// Since optional Complex arguments are not currently supported via the <chip::Optional> class,
// we will use mTimeZoneList.data() value to determine if the argument was provided.
Expand Down
17 changes: 16 additions & 1 deletion examples/chip-tool/commands/pairing/PairingCommand.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2020-2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -202,6 +202,18 @@ class PairingCommand : public CHIPCommand,
AddArgument("dst-offset", &mComplex_DSTOffsets,
"DSTOffset list to use when setting Time Synchronization cluster's DSTOffset attribute",
Argument::kOptional);

AddArgument("require-tc-acknowledgements", 0, 1, &mRequireTCAcknowledgements,
"Terms and Conditions acknowledgements is known to be required or not, (when required, the commissioner "
"will wait until they are provided)");

AddArgument("tc-acknowledgements", 0, UINT16_MAX, &mTCAcknowledgements,
"Terms and Conditions acknowledgements to use to set the General Commissioning cluster's TC "
"Acknowledgements bit-field");

AddArgument("tc-acknowledgements-version", 0, UINT16_MAX, &mTCAcknowledgementVersion,
"Terms and Conditions acknowledgement version to use to set the General Commissioning cluster's TC "
"Acknowledgement version");
}

AddArgument("timeout", 0, UINT16_MAX, &mTimeout);
Expand Down Expand Up @@ -259,6 +271,9 @@ class PairingCommand : public CHIPCommand,
chip::Optional<uint64_t> mICDMonitoredSubject;
chip::Optional<chip::app::Clusters::IcdManagement::ClientTypeEnum> mICDClientType;
chip::Optional<uint32_t> mICDStayActiveDurationMsec;
chip::Optional<bool> mRequireTCAcknowledgements;
chip::Optional<uint16_t> mTCAcknowledgements;
chip::Optional<uint16_t> mTCAcknowledgementVersion;
chip::app::DataModel::List<chip::app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type> mTimeZoneList;
TypedComplexArgument<chip::app::DataModel::List<chip::app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type>>
mComplex_TimeZones;
Expand Down
6 changes: 5 additions & 1 deletion src/controller/AutoCommissioner.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2021 Project CHIP Authors
* Copyright (c) 2021-2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -365,6 +365,10 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(Commissio
case CommissioningStage::kArmFailsafe:
return CommissioningStage::kConfigRegulatory;
case CommissioningStage::kConfigRegulatory:
return CommissioningStage::kGetTCAcknowledgments;
case CommissioningStage::kGetTCAcknowledgments:
return CommissioningStage::kConfigureTCAcknowledgments;
case CommissioningStage::kConfigureTCAcknowledgments:
if (mDeviceCommissioningInfo.requiresUTC)
{
return CommissioningStage::kConfigureUTCTime;
Expand Down
78 changes: 77 additions & 1 deletion src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2020-2022 Project CHIP Authors
* Copyright (c) 2020-2024 Project CHIP Authors
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
Expand Down Expand Up @@ -2691,6 +2691,22 @@ void DeviceCommissioner::OnSetRegulatoryConfigResponse(
commissioner->CommissioningStageComplete(err, report);
}

void DeviceCommissioner::OnSetTCAcknowledgementsResponse(
void * context, const GeneralCommissioning::Commands::SetTCAcknowledgementsResponse::DecodableType & data)
{
CommissioningDelegate::CommissioningReport report;
CHIP_ERROR err = CHIP_NO_ERROR;

ChipLogProgress(Controller, "Received SetTCAcknowledgements response errorCode=%u", to_underlying(data.errorCode));
if (data.errorCode != GeneralCommissioning::CommissioningErrorEnum::kOk)
{
err = CHIP_ERROR_INTERNAL;
report.Set<CommissioningErrorInfo>(data.errorCode);
}
DeviceCommissioner * commissioner = static_cast<DeviceCommissioner *>(context);
commissioner->CommissioningStageComplete(err, report);
}

void DeviceCommissioner::OnSetTimeZoneResponse(void * context,
const TimeSynchronization::Commands::SetTimeZoneResponse::DecodableType & data)
{
Expand Down Expand Up @@ -2766,6 +2782,16 @@ CHIP_ERROR DeviceCommissioner::ICDRegistrationInfoReady()
return CHIP_NO_ERROR;
}

CHIP_ERROR DeviceCommissioner::TermsAndConditionsAcknowledgementsReady()
{
ReturnErrorCodeIf(mCommissioningStage != CommissioningStage::kGetTCAcknowledgments, CHIP_ERROR_INCORRECT_STATE);

// need to advance to next step
CommissioningStageComplete(CHIP_NO_ERROR);

return CHIP_NO_ERROR;
}

void DeviceCommissioner::OnNetworkConfigResponse(void * context,
const NetworkCommissioning::Commands::NetworkConfigResponse::DecodableType & data)
{
Expand Down Expand Up @@ -3163,6 +3189,56 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio
}
}
break;
case CommissioningStage::kGetTCAcknowledgments: {
ChipLogProgress(Controller, "Get Terms and Conditions Acknowledgments");

bool acknowledgementReady = params.GetTermsAndConditionsAcknowledgement().HasValue();
bool acknowledgementNotRequired = params.GetRequireTermsAndConditionsAcknowledgement().HasValue() &&
!params.GetRequireTermsAndConditionsAcknowledgement().Value();

// If terms and conditions acknowledgements were provided, or not required, in the commissioning parameters, then skip ahead
if (acknowledgementReady || acknowledgementNotRequired)
{
TermsAndConditionsAcknowledgementsReady();
return;
}

ChipLogProgress(Controller, "Waiting for Terms and Conditions");
break;
}
case CommissioningStage::kConfigureTCAcknowledgments: {
ChipLogProgress(Controller, "Setting Terms and Conditions");

bool acknowledgementNotRequired = params.GetRequireTermsAndConditionsAcknowledgement().HasValue() &&
!params.GetRequireTermsAndConditionsAcknowledgement().Value();

if (acknowledgementNotRequired)
{
CommissioningStageComplete(CHIP_NO_ERROR);
return;
}

if (!params.GetTermsAndConditionsAcknowledgement().HasValue())
{
ChipLogError(Controller, "No acknowledgements provided");
CommissioningStageComplete(CHIP_ERROR_INVALID_ARGUMENT);
return;
}

GeneralCommissioning::Commands::SetTCAcknowledgements::Type request;
TermsAndConditionsAcknowledgement termsAndConditionsAcknowledgement = params.GetTermsAndConditionsAcknowledgement().Value();
request.TCUserResponse = termsAndConditionsAcknowledgement.acceptedTermsAndConditions;
request.TCVersion = termsAndConditionsAcknowledgement.acceptedTermsAndConditionsVersion;
CHIP_ERROR err =
SendCommissioningCommand(proxy, request, OnSetTCAcknowledgementsResponse, OnBasicFailure, endpoint, timeout);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Failed to send SetTCAcknowledgements command: %" CHIP_ERROR_FORMAT, err.Format());
CommissioningStageComplete(err);
return;
}
break;
}
case CommissioningStage::kSendPAICertificateRequest: {
ChipLogProgress(Controller, "Sending request for PAI certificate");
CHIP_ERROR err = SendCertificateChainRequestCommand(proxy, CertificateType::kPAI, timeout);
Expand Down
24 changes: 23 additions & 1 deletion src/controller/CHIPDeviceController.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2020-2022 Project CHIP Authors
* Copyright (c) 2020-2024 Project CHIP Authors
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
Expand Down Expand Up @@ -696,6 +696,25 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
*/
CHIP_ERROR ICDRegistrationInfoReady();

/**
* @brief
* This function is called by the upper layer application to indicate that the required terms and conditions
* acknowledgements have been set. This function should be called after the terms and conditions bitmask and version
* have been defined using the appropriate configuration macros and the application has gathered the necessary
* acknowledgements from the user.
*
* The upper layer application should call this method once it has successfully presented and obtained acknowledgements
* for the required terms and conditions from the user. This indicates that the commissioning process can advance to the
* next stage.
*
* When the terms and conditions acknowledgements process is completed, this function will signal the readiness to proceed
* to the next step in the commissioning process.
*
* @return CHIP_ERROR The return status. Returns CHIP_ERROR_INCORRECT_STATE if the function is called when the device
* is not in the correct state to accept terms and conditions acknowledgements.
*/
CHIP_ERROR TermsAndConditionsAcknowledgementsReady();

/**
* @brief
* This function returns the current CommissioningStage for this commissioner.
Expand Down Expand Up @@ -947,6 +966,9 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController,
static void OnSetRegulatoryConfigResponse(
void * context,
const chip::app::Clusters::GeneralCommissioning::Commands::SetRegulatoryConfigResponse::DecodableType & data);
static void OnSetTCAcknowledgementsResponse(
void * context,
const chip::app::Clusters::GeneralCommissioning::Commands::SetTCAcknowledgementsResponse::DecodableType & data);
static void OnSetUTCError(void * context, CHIP_ERROR error);
static void
OnSetTimeZoneResponse(void * context,
Expand Down
6 changes: 6 additions & 0 deletions src/controller/CommissioningDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ const char * StageToString(CommissioningStage stage)
case kConfigRegulatory:
return "ConfigRegulatory";

case kGetTCAcknowledgments:
return "GetTCAcknowledgments";

case kConfigureTCAcknowledgments:
return "ConfigureTCAcknowledgments";

case kConfigureUTCTime:
return "ConfigureUTCTime";

Expand Down
Loading

0 comments on commit bba6401

Please sign in to comment.