Skip to content

Commit

Permalink
[icd] read UserActiveModeTrigger during commissioning (#31039)
Browse files Browse the repository at this point in the history
* [icd] read UserActiveModeTrigger during commissioning

* Update CommissionerMain.cpp

fix typo

---------

Co-authored-by: yunhanw-google <yunhanw@google.com>
  • Loading branch information
erjiaqing and yunhanw-google authored Dec 21, 2023
1 parent 6d05eb6 commit 52f66e1
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 12 deletions.
25 changes: 25 additions & 0 deletions examples/chip-tool/commands/pairing/PairingCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,31 @@ void PairingCommand::OnCommissioningComplete(NodeId nodeId, CHIP_ERROR err)
SetCommandExitStatus(err);
}

void PairingCommand::OnReadCommissioningInfo(const Controller::ReadCommissioningInfo & info)
{
ChipLogProgress(AppServer, "OnReadCommissioningInfo - vendorId=0x%04X productId=0x%04X", info.basic.vendorId,
info.basic.productId);

// The string in CharSpan received from the device is not null-terminated, we use std::string here for coping and
// appending a numm-terminator at the end of the string.
std::string userActiveModeTriggerInstruction;

// Note: the callback doesn't own the buffer, should make a copy if it will be used it later.
if (info.icd.userActiveModeTriggerInstruction.size() != 0)
{
userActiveModeTriggerInstruction =
std::string(info.icd.userActiveModeTriggerInstruction.data(), info.icd.userActiveModeTriggerInstruction.size());
}

if (info.icd.userActiveModeTriggerHint.HasAny())
{
ChipLogProgress(AppServer, "OnReadCommissioningInfo - LIT UserActiveModeTriggerHint=0x%08x",
info.icd.userActiveModeTriggerHint.Raw());
ChipLogProgress(AppServer, "OnReadCommissioningInfo - LIT UserActiveModeTriggerInstruction=%s",
userActiveModeTriggerInstruction.c_str());
}
}

void PairingCommand::OnICDRegistrationComplete(NodeId nodeId, uint32_t icdCounter)
{
char icdSymmetricKeyHex[chip::Crypto::kAES_CCM128_Key_Length * 2 + 1];
Expand Down
1 change: 1 addition & 0 deletions examples/chip-tool/commands/pairing/PairingCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ class PairingCommand : public CHIPCommand,
void OnStatusUpdate(chip::Controller::DevicePairingDelegate::Status status) override;
void OnPairingComplete(CHIP_ERROR error) override;
void OnPairingDeleted(CHIP_ERROR error) override;
void OnReadCommissioningInfo(const chip::Controller::ReadCommissioningInfo & info) override;
void OnCommissioningComplete(NodeId deviceId, CHIP_ERROR error) override;
void OnICDRegistrationComplete(NodeId deviceId, uint32_t icdCounter) override;

Expand Down
23 changes: 22 additions & 1 deletion examples/platform/linux/CommissionerMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include <platform/CHIPDeviceLayer.h>
#include <platform/PlatformManager.h>

#include <string>

#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE

#include <app/clusters/network-commissioning/network-commissioning.h>
Expand Down Expand Up @@ -342,10 +344,29 @@ void PairingCommand::OnCommissioningStatusUpdate(PeerId peerId, CommissioningSta
}
}

void PairingCommand::OnReadCommissioningInfo(const ReadCommissioningInfo & info)
void PairingCommand::OnReadCommissioningInfo(const Controller::ReadCommissioningInfo & info)
{
ChipLogProgress(AppServer, "OnReadCommissioningInfo - vendorId=0x%04X productId=0x%04X", info.basic.vendorId,
info.basic.productId);

// The string in CharSpan received from the device is not null-terminated, we use std::string here for coping and
// appending a numm-terminator at the end of the string.
std::string userActiveModeTriggerInstruction;

// Note: the callback doesn't own the buffer, should make a copy if it will be used it later.
if (info.icd.userActiveModeTriggerInstruction.size() != 0)
{
userActiveModeTriggerInstruction =
std::string(info.icd.userActiveModeTriggerInstruction.data(), info.icd.userActiveModeTriggerInstruction.size());
}

if (info.icd.userActiveModeTriggerHint.HasAny())
{
ChipLogProgress(AppServer, "OnReadCommissioningInfo - LIT UserActiveModeTriggerHint=0x%08x",
info.icd.userActiveModeTriggerHint.Raw());
ChipLogProgress(AppServer, "OnReadCommissioningInfo - LIT UserActiveModeTriggerInstruction=%s",
userActiveModeTriggerInstruction.c_str());
}
}

void PairingCommand::OnFabricCheck(NodeId matchingNodeId)
Expand Down
2 changes: 1 addition & 1 deletion src/controller/AutoCommissioner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ CHIP_ERROR AutoCommissioner::CommissioningStepFinished(CHIP_ERROR err, Commissio

if (mParams.GetICDRegistrationStrategy() != ICDRegistrationStrategy::kIgnore)
{
if (commissioningInfo.isLIT && commissioningInfo.checkInProtocolSupport)
if (commissioningInfo.icd.isLIT && commissioningInfo.icd.checkInProtocolSupport)
{
mNeedIcdRegistration = true;
ChipLogDetail(Controller, "AutoCommissioner: ICD supports the check-in protocol.");
Expand Down
71 changes: 63 additions & 8 deletions src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1950,7 +1950,13 @@ void DeviceCommissioner::ParseCommissioningInfo()
err = ParseCommissioningInfo2(info);
}

mAttributeCache = nullptr;
// Move ownership of mAttributeCache to the stack, but don't release it until this function returns.
// This way we don't have to make a copy while parsing commissioning info, and it won't
// affect future commissioning steps.
//
// The stack reference needs to survive until CommissioningStageComplete and OnReadCommissioningInfo
// return.
auto attributeCache = std::move(mAttributeCache);

if (mPairingDelegate != nullptr)
{
Expand Down Expand Up @@ -2265,21 +2271,24 @@ CHIP_ERROR DeviceCommissioner::ParseFabrics(ReadCommissioningInfo & info)

CHIP_ERROR DeviceCommissioner::ParseICDInfo(ReadCommissioningInfo & info)
{
using chip::app::Clusters::IcdManagement::UserActiveModeTriggerBitmap;

CHIP_ERROR err;
IcdManagement::Attributes::FeatureMap::TypeInfo::DecodableType featureMap;
bool hasUserActiveModeTrigger = false;

err = mAttributeCache->Get<IcdManagement::Attributes::FeatureMap::TypeInfo>(kRootEndpointId, featureMap);
if (err == CHIP_NO_ERROR)
{
info.isLIT = true;
info.checkInProtocolSupport = !!(featureMap & to_underlying(IcdManagement::Feature::kCheckInProtocolSupport));
info.icd.isLIT = !!(featureMap & to_underlying(IcdManagement::Feature::kLongIdleTimeSupport));
info.icd.checkInProtocolSupport = !!(featureMap & to_underlying(IcdManagement::Feature::kCheckInProtocolSupport));
hasUserActiveModeTrigger = !!(featureMap & to_underlying(IcdManagement::Feature::kUserActiveModeTrigger));
}
else if (err == CHIP_ERROR_KEY_NOT_FOUND)
{
// This key is optional so not an error
err = CHIP_NO_ERROR;
info.isLIT = false;
err = CHIP_NO_ERROR;
info.icd.isLIT = false;
err = CHIP_NO_ERROR;
}
else if (err == CHIP_ERROR_IM_STATUS_CODE_RECEIVED)
{
Expand All @@ -2290,7 +2299,7 @@ CHIP_ERROR DeviceCommissioner::ParseICDInfo(ReadCommissioningInfo & info)
{
if (statusIB.mStatus == Protocols::InteractionModel::Status::UnsupportedCluster)
{
info.isLIT = false;
info.icd.isLIT = false;
}
else
{
Expand All @@ -2299,6 +2308,45 @@ CHIP_ERROR DeviceCommissioner::ParseICDInfo(ReadCommissioningInfo & info)
}
}

ReturnErrorOnFailure(err);

info.icd.userActiveModeTriggerHint.ClearAll();
info.icd.userActiveModeTriggerInstruction = CharSpan();
if (hasUserActiveModeTrigger)
{
// Intentionally ignore errors since they are not mandatory.
bool activeModeTriggerInstructionRequired = false;

err = mAttributeCache->Get<IcdManagement::Attributes::UserActiveModeTriggerHint::TypeInfo>(
kRootEndpointId, info.icd.userActiveModeTriggerHint);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "IcdManagement.UserActiveModeTriggerHint expected, but failed to read.");
return err;
}

activeModeTriggerInstructionRequired = info.icd.userActiveModeTriggerHint.HasAny(
UserActiveModeTriggerBitmap::kCustomInstruction, UserActiveModeTriggerBitmap::kActuateSensorSeconds,
UserActiveModeTriggerBitmap::kActuateSensorTimes, UserActiveModeTriggerBitmap::kActuateSensorLightsBlink,
UserActiveModeTriggerBitmap::kResetButtonLightsBlink, UserActiveModeTriggerBitmap::kResetButtonSeconds,
UserActiveModeTriggerBitmap::kResetButtonTimes, UserActiveModeTriggerBitmap::kSetupButtonSeconds,
UserActiveModeTriggerBitmap::kSetupButtonTimes, UserActiveModeTriggerBitmap::kSetupButtonTimes,
UserActiveModeTriggerBitmap::kAppDefinedButton);

if (activeModeTriggerInstructionRequired)
{
err = mAttributeCache->Get<IcdManagement::Attributes::UserActiveModeTriggerInstruction::TypeInfo>(
kRootEndpointId, info.icd.userActiveModeTriggerInstruction);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller,
"IcdManagement.UserActiveModeTriggerInstruction expected for given active mode trigger hint, but "
"failed to read.");
return err;
}
}
}

return err;
}

Expand Down Expand Up @@ -2565,7 +2613,9 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio
// This is done in a separate step since we've already used up all the available read paths in the previous read step
// NOTE: this array cannot have more than 9 entries, since the spec mandates that server only needs to support 9
// See R1.1, 2.11.2 Interaction Model Limits
app::AttributePathParams readPaths[3];

// Currently, we have at most 5 attributes to read in this stage.
app::AttributePathParams readPaths[5];

// Mandatory attribute
readPaths[numberOfAttributes++] =
Expand All @@ -2584,6 +2634,11 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio
readPaths[numberOfAttributes++] =
app::AttributePathParams(endpoint, IcdManagement::Id, IcdManagement::Attributes::FeatureMap::Id);
}
// Always read the active mode trigger hint attributes to notify users about it.
readPaths[numberOfAttributes++] =
app::AttributePathParams(endpoint, IcdManagement::Id, IcdManagement::Attributes::UserActiveModeTriggerHint::Id);
readPaths[numberOfAttributes++] =
app::AttributePathParams(endpoint, IcdManagement::Id, IcdManagement::Attributes::UserActiveModeTriggerInstruction::Id);

SendCommissioningReadRequest(proxy, timeout, readPaths, numberOfAttributes);
}
Expand Down
23 changes: 21 additions & 2 deletions src/controller/CommissioningDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,26 @@ struct GeneralCommissioningInfo
;
};

// ICDManagementClusterInfo is populated when the controller reads information from
// the ICD Management cluster, and is used to communicate that information.
struct ICDManagementClusterInfo
{
// Whether the ICD is capable of functioning as a LIT device. If false, the ICD can only be a SIT device.
bool isLIT;
// Whether the ICD supports the check-in protocol. LIT devices have to support it, but SIT devices
// might or might not.
bool checkInProtocolSupport;

// userActiveModeTriggerHint indicates which user action(s) will trigger the ICD to switch to Active mode.
// For a LIT: The device is required to provide a value for the bitmap.
// For a SIT: The device may not provide a value. In that case, none of the bits will be set.
//
// userActiveModeTriggerInstruction may provide additional information for users for some specific
// userActiveModeTriggerHint values.
BitMask<app::Clusters::IcdManagement::UserActiveModeTriggerBitmap> userActiveModeTriggerHint;
CharSpan userActiveModeTriggerInstruction;
};

struct ReadCommissioningInfo
{
NetworkClusters network;
Expand All @@ -691,9 +711,8 @@ struct ReadCommissioningInfo
uint8_t maxTimeZoneSize = 1;
uint8_t maxDSTSize = 1;
NodeId remoteNodeId = kUndefinedNodeId;
bool isLIT = false;
bool checkInProtocolSupport = false;
bool supportsConcurrentConnection = true;
ICDManagementClusterInfo icd;
};

struct TimeZoneResponseInfo
Expand Down

0 comments on commit 52f66e1

Please sign in to comment.