diff --git a/docs/cluster_and_device_type_dev/img/cluster_commands.png b/docs/cluster_and_device_type_dev/img/cluster_commands.png index c04dbe7279b28b..7df7a8a75412ab 100644 Binary files a/docs/cluster_and_device_type_dev/img/cluster_commands.png and b/docs/cluster_and_device_type_dev/img/cluster_commands.png differ diff --git a/examples/chef/common/chef-operational-state-delegate-impl.cpp b/examples/chef/common/chef-operational-state-delegate-impl.cpp new file mode 100644 index 00000000000000..48863b0cfa6c26 --- /dev/null +++ b/examples/chef/common/chef-operational-state-delegate-impl.cpp @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::OperationalState; +using namespace chip::app::Clusters::RvcOperationalState; + +static void onOperationalStateTimerTick(System::Layer * systemLayer, void * data); + +DataModel::Nullable GenericOperationalStateDelegateImpl::GetCountdownTime() +{ + if (mCountDownTime.IsNull()) + return DataModel::NullNullable; + + return DataModel::MakeNullable((uint32_t) (mCountDownTime.Value() - mRunningTime)); +} + +CHIP_ERROR GenericOperationalStateDelegateImpl::GetOperationalStateAtIndex(size_t index, GenericOperationalState & operationalState) +{ + if (index >= mOperationalStateList.size()) + { + return CHIP_ERROR_NOT_FOUND; + } + operationalState = mOperationalStateList[index]; + return CHIP_NO_ERROR; +} + +CHIP_ERROR GenericOperationalStateDelegateImpl::GetOperationalPhaseAtIndex(size_t index, MutableCharSpan & operationalPhase) +{ + if (index >= mOperationalPhaseList.size()) + { + return CHIP_ERROR_NOT_FOUND; + } + return CopyCharSpanToMutableCharSpan(mOperationalPhaseList[index], operationalPhase); +} + +void GenericOperationalStateDelegateImpl::HandlePauseStateCallback(GenericOperationalError & err) +{ + OperationalState::OperationalStateEnum state = + static_cast(GetInstance()->GetCurrentOperationalState()); + + if (state == OperationalState::OperationalStateEnum::kStopped || state == OperationalState::OperationalStateEnum::kError) + { + err.Set(to_underlying(OperationalState::ErrorStateEnum::kCommandInvalidInState)); + return; + } + + // placeholder implementation + auto error = GetInstance()->SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kPaused)); + if (error == CHIP_NO_ERROR) + { + err.Set(to_underlying(ErrorStateEnum::kNoError)); + } + else + { + err.Set(to_underlying(ErrorStateEnum::kUnableToCompleteOperation)); + } +} + +void GenericOperationalStateDelegateImpl::HandleResumeStateCallback(GenericOperationalError & err) +{ + OperationalState::OperationalStateEnum state = + static_cast(GetInstance()->GetCurrentOperationalState()); + + if (state == OperationalState::OperationalStateEnum::kStopped || state == OperationalState::OperationalStateEnum::kError) + { + err.Set(to_underlying(OperationalState::ErrorStateEnum::kCommandInvalidInState)); + return; + } + + // placeholder implementation + auto error = GetInstance()->SetOperationalState(to_underlying(OperationalStateEnum::kRunning)); + if (error == CHIP_NO_ERROR) + { + err.Set(to_underlying(ErrorStateEnum::kNoError)); + } + else + { + err.Set(to_underlying(ErrorStateEnum::kUnableToCompleteOperation)); + } +} + +void GenericOperationalStateDelegateImpl::HandleStartStateCallback(GenericOperationalError & err) +{ + OperationalState::GenericOperationalError current_err(to_underlying(OperationalState::ErrorStateEnum::kNoError)); + GetInstance()->GetCurrentOperationalError(current_err); + + if (current_err.errorStateID != to_underlying(OperationalState::ErrorStateEnum::kNoError)) + { + err.Set(to_underlying(OperationalState::ErrorStateEnum::kUnableToStartOrResume)); + return; + } + + // placeholder implementation + auto error = GetInstance()->SetOperationalState(to_underlying(OperationalStateEnum::kRunning)); + if (error == CHIP_NO_ERROR) + { + (void) DeviceLayer::SystemLayer().StartTimer(System::Clock::Seconds16(1), onOperationalStateTimerTick, this); + err.Set(to_underlying(ErrorStateEnum::kNoError)); + } + else + { + err.Set(to_underlying(ErrorStateEnum::kUnableToCompleteOperation)); + } +} + +void GenericOperationalStateDelegateImpl::HandleStopStateCallback(GenericOperationalError & err) +{ + // placeholder implementation + auto error = GetInstance()->SetOperationalState(to_underlying(OperationalStateEnum::kStopped)); + if (error == CHIP_NO_ERROR) + { + (void) DeviceLayer::SystemLayer().CancelTimer(onOperationalStateTimerTick, this); + + OperationalState::GenericOperationalError current_err(to_underlying(OperationalState::ErrorStateEnum::kNoError)); + GetInstance()->GetCurrentOperationalError(current_err); + + Optional> totalTime((DataModel::Nullable(mRunningTime + mPausedTime))); + Optional> pausedTime((DataModel::Nullable(mPausedTime))); + + GetInstance()->OnOperationCompletionDetected(static_cast(current_err.errorStateID), totalTime, pausedTime); + + mRunningTime = 0; + mPausedTime = 0; + err.Set(to_underlying(ErrorStateEnum::kNoError)); + } + else + { + err.Set(to_underlying(ErrorStateEnum::kUnableToCompleteOperation)); + } +} + +static void onOperationalStateTimerTick(System::Layer * systemLayer, void * data) +{ + GenericOperationalStateDelegateImpl * delegate = reinterpret_cast(data); + + OperationalState::Instance * instance = OperationalState::GetOperationalStateInstance(); + OperationalState::OperationalStateEnum state = + static_cast(instance->GetCurrentOperationalState()); + + auto countdown_time = delegate->GetCountdownTime(); + + if (countdown_time.IsNull() || (!countdown_time.IsNull() && countdown_time.Value() > 0)) + { + if (state == OperationalState::OperationalStateEnum::kRunning) + { + delegate->mRunningTime++; + } + else if (state == OperationalState::OperationalStateEnum::kPaused) + { + delegate->mPausedTime++; + } + } + + if (state == OperationalState::OperationalStateEnum::kRunning || state == OperationalState::OperationalStateEnum::kPaused) + { + (void) DeviceLayer::SystemLayer().StartTimer(System::Clock::Seconds16(1), onOperationalStateTimerTick, delegate); + } + else + { + (void) DeviceLayer::SystemLayer().CancelTimer(onOperationalStateTimerTick, delegate); + } +} + +// Init Operational State cluster + +static OperationalState::Instance * gOperationalStateInstance = nullptr; +static OperationalStateDelegate * gOperationalStateDelegate = nullptr; + +OperationalState::Instance * OperationalState::GetOperationalStateInstance() +{ + return gOperationalStateInstance; +} + +void OperationalState::Shutdown() +{ + if (gOperationalStateInstance != nullptr) + { + delete gOperationalStateInstance; + gOperationalStateInstance = nullptr; + } + if (gOperationalStateDelegate != nullptr) + { + delete gOperationalStateDelegate; + gOperationalStateDelegate = nullptr; + } +} + +void emberAfOperationalStateClusterInitCallback(chip::EndpointId endpointId) +{ + VerifyOrDie(endpointId == 1); // this cluster is only enabled for endpoint 1. + VerifyOrDie(gOperationalStateInstance == nullptr && gOperationalStateDelegate == nullptr); + + gOperationalStateDelegate = new OperationalStateDelegate; + EndpointId operationalStateEndpoint = 0x01; + gOperationalStateInstance = new OperationalState::Instance(gOperationalStateDelegate, operationalStateEndpoint); + + gOperationalStateInstance->SetOperationalState(to_underlying(OperationalState::OperationalStateEnum::kStopped)); + + gOperationalStateInstance->Init(); +} diff --git a/examples/chef/common/chef-operational-state-delegate-impl.h b/examples/chef/common/chef-operational-state-delegate-impl.h new file mode 100644 index 00000000000000..60b6b09e9b6511 --- /dev/null +++ b/examples/chef/common/chef-operational-state-delegate-impl.h @@ -0,0 +1,147 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +namespace chip { +namespace app { +namespace Clusters { + +namespace OperationalState { + +// This is an application level delegate to handle operational state commands according to the specific business logic. +class GenericOperationalStateDelegateImpl : public Delegate +{ +public: + uint32_t mRunningTime = 0; + uint32_t mPausedTime = 0; + app::DataModel::Nullable mCountDownTime; + + /** + * Get the countdown time. This attribute is not used in this application. + * @return The current countdown time. + */ + app::DataModel::Nullable GetCountdownTime() override; + + /** + * Fills in the provided GenericOperationalState with the state at index `index` if there is one, + * or returns CHIP_ERROR_NOT_FOUND if the index is out of range for the list of states. + * Note: This is used by the SDK to populate the operational state list attribute. If the contents of this list changes, + * the device SHALL call the Instance's ReportOperationalStateListChange method to report that this attribute has changed. + * @param index The index of the state, with 0 representing the first state. + * @param operationalState The GenericOperationalState is filled. + */ + CHIP_ERROR GetOperationalStateAtIndex(size_t index, GenericOperationalState & operationalState) override; + + /** + * Fills in the provided MutableCharSpan with the phase at index `index` if there is one, + * or returns CHIP_ERROR_NOT_FOUND if the index is out of range for the list of phases. + * + * If CHIP_ERROR_NOT_FOUND is returned for index 0, that indicates that the PhaseList attribute is null + * (there are no phases defined at all). + * + * Note: This is used by the SDK to populate the phase list attribute. If the contents of this list changes, the + * device SHALL call the Instance's ReportPhaseListChange method to report that this attribute has changed. + * @param index The index of the phase, with 0 representing the first phase. + * @param operationalPhase The MutableCharSpan is filled. + */ + CHIP_ERROR GetOperationalPhaseAtIndex(size_t index, MutableCharSpan & operationalPhase) override; + + // command callback + /** + * Handle Command Callback in application: Pause + * @param[out] get operational error after callback. + */ + void HandlePauseStateCallback(GenericOperationalError & err) override; + + /** + * Handle Command Callback in application: Resume + * @param[out] get operational error after callback. + */ + void HandleResumeStateCallback(GenericOperationalError & err) override; + + /** + * Handle Command Callback in application: Start + * @param[out] get operational error after callback. + */ + void HandleStartStateCallback(GenericOperationalError & err) override; + + /** + * Handle Command Callback in application: Stop + * @param[out] get operational error after callback. + */ + void HandleStopStateCallback(GenericOperationalError & err) override; + +protected: + Span mOperationalStateList; + Span mOperationalPhaseList; +}; + +// This is an application level delegate to handle operational state commands according to the specific business logic. +class OperationalStateDelegate : public GenericOperationalStateDelegateImpl +{ +private: + const GenericOperationalState opStateList[4] = { + GenericOperationalState(to_underlying(OperationalStateEnum::kStopped)), + GenericOperationalState(to_underlying(OperationalStateEnum::kRunning)), + GenericOperationalState(to_underlying(OperationalStateEnum::kPaused)), + GenericOperationalState(to_underlying(OperationalStateEnum::kError)), + }; + + const uint32_t kExampleCountDown = 30; + +public: + OperationalStateDelegate() + { + GenericOperationalStateDelegateImpl::mOperationalStateList = Span(opStateList); + } + + /** + * Handle Command Callback in application: Start + * @param[out] get operational error after callback. + */ + void HandleStartStateCallback(GenericOperationalError & err) override + { + mCountDownTime.SetNonNull(static_cast(kExampleCountDown)); + GenericOperationalStateDelegateImpl::HandleStartStateCallback(err); + } + + /** + * Handle Command Callback in application: Stop + * @param[out] get operational error after callback. + */ + void HandleStopStateCallback(GenericOperationalError & err) override + { + GenericOperationalStateDelegateImpl::HandleStopStateCallback(err); + mCountDownTime.SetNull(); + } +}; + +Instance * GetOperationalStateInstance(); + +void Shutdown(); + +} // namespace OperationalState +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/chef/linux/BUILD.gn b/examples/chef/linux/BUILD.gn index 02fa77dac864e5..0a4e2385f28dda 100644 --- a/examples/chef/linux/BUILD.gn +++ b/examples/chef/linux/BUILD.gn @@ -43,6 +43,7 @@ executable("${sample_name}") { "${project_dir}/common/chef-air-quality.cpp", "${project_dir}/common/chef-concentration-measurement.cpp", "${project_dir}/common/chef-fan-control-manager.cpp", + "${project_dir}/common/chef-operational-state-delegate-impl.cpp", "${project_dir}/common/chef-resource-monitoring-delegates.cpp", "${project_dir}/common/chef-rvc-mode-delegate.cpp", "${project_dir}/common/chef-rvc-operational-state-delegate.cpp", diff --git a/examples/chef/nrfconnect/CMakeLists.txt b/examples/chef/nrfconnect/CMakeLists.txt index 0a408e829dd04f..25d663211b9f15 100644 --- a/examples/chef/nrfconnect/CMakeLists.txt +++ b/examples/chef/nrfconnect/CMakeLists.txt @@ -84,6 +84,7 @@ target_sources(app PRIVATE ${CHEF}/common/chef-air-quality.cpp ${CHEF}/common/chef-concentration-measurement.cpp ${CHEF}/common/chef-fan-control-manager.cpp + ${CHEF}/common/chef-operational-state-delegate-impl.cpp ${CHEF}/common/chef-resource-monitoring-delegates.cpp ${CHEF}/common/chef-rvc-mode-delegate.cpp ${CHEF}/common/chef-rvc-operational-state-delegate.cpp diff --git a/examples/light-switch-app/light-switch-common/light-switch-app.matter b/examples/light-switch-app/light-switch-common/light-switch-app.matter index 65bef372495d85..e51a772add14e2 100644 --- a/examples/light-switch-app/light-switch-common/light-switch-app.matter +++ b/examples/light-switch-app/light-switch-common/light-switch-app.matter @@ -2628,6 +2628,7 @@ endpoint 0 { ram attribute clusterRevision default = 1; handle command RetrieveLogsRequest; + handle command RetrieveLogsResponse; } server cluster GeneralDiagnostics { diff --git a/examples/light-switch-app/light-switch-common/light-switch-app.zap b/examples/light-switch-app/light-switch-common/light-switch-app.zap index 2c61c123c83437..ba56db35a2669b 100644 --- a/examples/light-switch-app/light-switch-common/light-switch-app.zap +++ b/examples/light-switch-app/light-switch-common/light-switch-app.zap @@ -1581,6 +1581,14 @@ "source": "client", "isIncoming": 1, "isEnabled": 1 + }, + { + "name": "RetrieveLogsResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 } ], "attributes": [ @@ -4605,6 +4613,24 @@ "define": "IDENTIFY_CLUSTER", "side": "client", "enabled": 1, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "TriggerEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + } + ], "attributes": [ { "name": "ClusterRevision", diff --git a/examples/lock-app/lock-common/lock-app.matter b/examples/lock-app/lock-common/lock-app.matter index b886f3e52d067a..8fee37c9493c67 100644 --- a/examples/lock-app/lock-common/lock-app.matter +++ b/examples/lock-app/lock-common/lock-app.matter @@ -2663,6 +2663,7 @@ endpoint 0 { ram attribute clusterRevision default = 1; handle command RetrieveLogsRequest; + handle command RetrieveLogsResponse; } server cluster GeneralDiagnostics { diff --git a/examples/lock-app/lock-common/lock-app.zap b/examples/lock-app/lock-common/lock-app.zap index 0c9ce257b3cf31..04689b5ca64a00 100644 --- a/examples/lock-app/lock-common/lock-app.zap +++ b/examples/lock-app/lock-common/lock-app.zap @@ -2126,6 +2126,14 @@ "source": "client", "isIncoming": 1, "isEnabled": 1 + }, + { + "name": "RetrieveLogsResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 } ], "attributes": [ diff --git a/examples/thermostat/thermostat-common/thermostat.matter b/examples/thermostat/thermostat-common/thermostat.matter index d821e6a6d609f6..60427f9ac0f854 100644 --- a/examples/thermostat/thermostat-common/thermostat.matter +++ b/examples/thermostat/thermostat-common/thermostat.matter @@ -2097,6 +2097,7 @@ endpoint 0 { server cluster Identify { ram attribute identifyTime default = 0x0000; + ram attribute identifyType default = 0x00; ram attribute featureMap default = 0; ram attribute clusterRevision default = 4; @@ -2240,6 +2241,7 @@ endpoint 0 { ram attribute clusterRevision default = 1; handle command RetrieveLogsRequest; + handle command RetrieveLogsResponse; } server cluster GeneralDiagnostics { diff --git a/examples/thermostat/thermostat-common/thermostat.zap b/examples/thermostat/thermostat-common/thermostat.zap index 79396ba5d313c4..64c87bce7e15c6 100644 --- a/examples/thermostat/thermostat-common/thermostat.zap +++ b/examples/thermostat/thermostat-common/thermostat.zap @@ -94,6 +94,22 @@ "maxInterval": 65344, "reportableChange": 0 }, + { + "name": "IdentifyType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "IdentifyTypeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "FeatureMap", "code": 65532, @@ -1707,6 +1723,14 @@ "source": "client", "isIncoming": 1, "isEnabled": 1 + }, + { + "name": "RetrieveLogsResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 } ], "attributes": [ diff --git a/src/app/CommandHandler.cpp b/src/app/CommandHandler.cpp index d0e5db94197e0d..8170b57abd7d23 100644 --- a/src/app/CommandHandler.cpp +++ b/src/app/CommandHandler.cpp @@ -595,7 +595,17 @@ void CommandHandler::AddStatus(const ConcreteCommandPath & aCommandPath, const P { // Return early in case of requests targeted to a group, since they should not add a response. VerifyOrReturn(!IsGroupRequest()); - VerifyOrDie(FallibleAddStatus(aCommandPath, aStatus, context) == CHIP_NO_ERROR); + + CHIP_ERROR error = FallibleAddStatus(aCommandPath, aStatus, context); + + if (error != CHIP_NO_ERROR) + { + ChipLogError(DataManagement, "Failed to add command status: %" CHIP_ERROR_FORMAT, error.Format()); + + // Do not crash if the status has not been added due to running out of packet buffers or other resources. + // It is better to drop a single response than to go offline and lose all sessions and subscriptions. + VerifyOrDie(error == CHIP_ERROR_NO_MEMORY); + } } CHIP_ERROR CommandHandler::FallibleAddStatus(const ConcreteCommandPath & path, const Protocols::InteractionModel::Status status, diff --git a/src/app/OperationalSessionSetup.cpp b/src/app/OperationalSessionSetup.cpp index 179e2a3df5e120..6df07ca6b0568e 100644 --- a/src/app/OperationalSessionSetup.cpp +++ b/src/app/OperationalSessionSetup.cpp @@ -430,7 +430,7 @@ void OperationalSessionSetup::OnSessionEstablishmentError(CHIP_ERROR error, Sess // member instead of having a boolean // mTryingNextResultDueToSessionEstablishmentError, so we can recover the // error in UpdateDeviceData. - if (CHIP_ERROR_TIMEOUT == error) + if (CHIP_ERROR_TIMEOUT == error || CHIP_ERROR_BUSY == error) { #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES // Make a copy of the ReliableMessageProtocolConfig, since our @@ -480,6 +480,15 @@ void OperationalSessionSetup::OnSessionEstablishmentError(CHIP_ERROR error, Sess // Do not touch `this` instance anymore; it has been destroyed in DequeueConnectionCallbacks. } +void OperationalSessionSetup::OnResponderBusy(System::Clock::Milliseconds16 requestedDelay) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES + // Store the requested delay, so that we can use it for scheduling our + // retry. + mRequestedBusyDelay = requestedDelay; +#endif +} + void OperationalSessionSetup::OnSessionEstablished(const SessionHandle & session) { VerifyOrReturn(mState == State::Connecting, @@ -705,9 +714,22 @@ CHIP_ERROR OperationalSessionSetup::ScheduleSessionSetupReattempt(System::Clock: static_assert(UINT16_MAX / CHIP_DEVICE_CONFIG_AUTOMATIC_CASE_RETRY_INITIAL_DELAY_SECONDS >= (1 << CHIP_DEVICE_CONFIG_AUTOMATIC_CASE_RETRY_MAX_BACKOFF), "Our backoff calculation will overflow."); - timerDelay = System::Clock::Seconds16( + System::Clock::Timeout actualTimerDelay = System::Clock::Seconds16( static_cast(CHIP_DEVICE_CONFIG_AUTOMATIC_CASE_RETRY_INITIAL_DELAY_SECONDS << min((mAttemptsDone - 1), CHIP_DEVICE_CONFIG_AUTOMATIC_CASE_RETRY_MAX_BACKOFF))); + const bool responseWasBusy = mRequestedBusyDelay != System::Clock::kZero; + if (responseWasBusy) + { + if (mRequestedBusyDelay > actualTimerDelay) + { + actualTimerDelay = mRequestedBusyDelay; + } + + // Reset mRequestedBusyDelay now that we have consumed it, so it does + // not affect future reattempts not triggered by a busy response. + mRequestedBusyDelay = System::Clock::kZero; + } + if (mAttemptsDone % 2 == 0) { // It's possible that the other side received one of our Sigma1 messages @@ -716,11 +738,22 @@ CHIP_ERROR OperationalSessionSetup::ScheduleSessionSetupReattempt(System::Clock: // listening for Sigma1 messages again. // // To handle that, on every other retry, add the amount of time it would - // take the other side to time out. + // take the other side to time out. It would be nice if we could rely + // on the delay reported in a BUSY response to just tell us that value, + // but in practice for old devices BUSY often sends some hardcoded value + // that tells us nothing about when the other side will decide it has + // timed out. auto additionalTimeout = CASESession::ComputeSigma2ResponseTimeout(GetLocalMRPConfig().ValueOr(GetDefaultMRPConfig())); - timerDelay += std::chrono::duration_cast(additionalTimeout); + actualTimerDelay += additionalTimeout; } - CHIP_ERROR err = mInitParams.exchangeMgr->GetSessionManager()->SystemLayer()->StartTimer(timerDelay, TrySetupAgain, this); + timerDelay = std::chrono::duration_cast(actualTimerDelay); + + CHIP_ERROR err = mInitParams.exchangeMgr->GetSessionManager()->SystemLayer()->StartTimer(actualTimerDelay, TrySetupAgain, this); + + // TODO: If responseWasBusy, should we increment, mRemainingAttempts and + // mResolveAttemptsAllowed, since we were explicitly told to retry? Hard to + // tell what consumers expect out of a capped retry count here. + // The cast on count() is needed because the type count() returns might not // actually be uint16_t; on some platforms it's int. ChipLogProgress(Discovery, diff --git a/src/app/OperationalSessionSetup.h b/src/app/OperationalSessionSetup.h index 45b571a08aa633..9d24faad5efabb 100644 --- a/src/app/OperationalSessionSetup.h +++ b/src/app/OperationalSessionSetup.h @@ -227,6 +227,7 @@ class DLL_EXPORT OperationalSessionSetup : public SessionEstablishmentDelegate, //////////// SessionEstablishmentDelegate Implementation /////////////// void OnSessionEstablished(const SessionHandle & session) override; void OnSessionEstablishmentError(CHIP_ERROR error, SessionEstablishmentStage stage) override; + void OnResponderBusy(System::Clock::Milliseconds16 requestedDelay) override; ScopedNodeId GetPeerId() const { return mPeerId; } @@ -319,6 +320,8 @@ class DLL_EXPORT OperationalSessionSetup : public SessionEstablishmentDelegate, uint8_t mResolveAttemptsAllowed = 0; + System::Clock::Milliseconds16 mRequestedBusyDelay = System::Clock::kZero; + Callback::CallbackDeque mConnectionRetry; #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES diff --git a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml index 259a59dae3ead5..96ed6fdc2da625 100644 --- a/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml +++ b/src/app/zap-templates/zcl/data-model/chip/matter-devices.xml @@ -74,10 +74,10 @@ limitations under the License. ACTIVE_LOCALE SUPPORTED_LOCALES - + HOUR_FORMAT - + UP_TIME @@ -1417,7 +1417,6 @@ limitations under the License. IDENTIFY_TYPE Identify IdentifyQuery - TriggerEffect DEVICE_TYPE_LIST @@ -1475,7 +1474,6 @@ limitations under the License. IDENTIFY_TYPE Identify IdentifyQuery - TriggerEffect DEVICE_TYPE_LIST diff --git a/src/controller/CommissioningDelegate.h b/src/controller/CommissioningDelegate.h index 175c246e908f9d..2a78663541dd49 100644 --- a/src/controller/CommissioningDelegate.h +++ b/src/controller/CommissioningDelegate.h @@ -370,9 +370,12 @@ class CommissioningParameters mAttestationNonce.SetValue(attestationNonce); return *this; } + + // If a WiFiCredentials is provided, then the WiFiNetworkScan will not be attempted CommissioningParameters & SetWiFiCredentials(WiFiCredentials wifiCreds) { mWiFiCreds.SetValue(wifiCreds); + mAttemptWiFiNetworkScan.SetValue(false); return *this; } diff --git a/src/controller/java/AndroidDeviceControllerWrapper.cpp b/src/controller/java/AndroidDeviceControllerWrapper.cpp index 74e1187ef2a03b..c965bb0f17584b 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.cpp +++ b/src/controller/java/AndroidDeviceControllerWrapper.cpp @@ -104,7 +104,7 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew( jobject keypairDelegate, jbyteArray rootCertificate, jbyteArray intermediateCertificate, jbyteArray nodeOperationalCertificate, jbyteArray ipkEpochKey, uint16_t listenPort, uint16_t controllerVendorId, uint16_t failsafeTimerSeconds, bool attemptNetworkScanWiFi, bool attemptNetworkScanThread, bool skipCommissioningComplete, - bool skipAttestationCertificateValidation, CHIP_ERROR * errInfoOnFailure) + bool skipAttestationCertificateValidation, jstring countryCode, CHIP_ERROR * errInfoOnFailure) { if (errInfoOnFailure == nullptr) { @@ -207,11 +207,30 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew( wrapper->mGroupDataProvider.SetStorageDelegate(wrapperStorage); wrapper->mGroupDataProvider.SetSessionKeystore(initParams.sessionKeystore); - CommissioningParameters params = wrapper->mAutoCommissioner.GetCommissioningParameters(); + CommissioningParameters params = wrapper->GetCommissioningParameters(); params.SetFailsafeTimerSeconds(failsafeTimerSeconds); params.SetAttemptWiFiNetworkScan(attemptNetworkScanWiFi); params.SetAttemptThreadNetworkScan(attemptNetworkScanThread); params.SetSkipCommissioningComplete(skipCommissioningComplete); + + if (countryCode != nullptr) + { + JniUtfString countryCodeJniString(env, countryCode); + if (countryCodeJniString.size() != kCountryCodeBufferLen) + { + *errInfoOnFailure = CHIP_ERROR_INVALID_ARGUMENT; + return nullptr; + } + + MutableCharSpan copiedCode(wrapper->mCountryCode); + if (CopyCharSpanToMutableCharSpan(countryCodeJniString.charSpan(), copiedCode) != CHIP_NO_ERROR) + { + *errInfoOnFailure = CHIP_ERROR_INVALID_ARGUMENT; + return nullptr; + } + params.SetCountryCode(copiedCode); + } + wrapper->UpdateCommissioningParameters(params); CHIP_ERROR err = wrapper->mGroupDataProvider.Init(); @@ -526,6 +545,7 @@ CHIP_ERROR AndroidDeviceControllerWrapper::UpdateCommissioningParameters(const c { // this will wipe out any custom attestationNonce and csrNonce that was being used. // however, Android APIs don't allow these to be set to custom values today. + mCommissioningParameter = params; return mAutoCommissioner.SetCommissioningParameters(params); } diff --git a/src/controller/java/AndroidDeviceControllerWrapper.h b/src/controller/java/AndroidDeviceControllerWrapper.h index ac279370f62c4a..5ccb2edb3b2050 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.h +++ b/src/controller/java/AndroidDeviceControllerWrapper.h @@ -50,6 +50,8 @@ constexpr uint8_t kUserActiveModeTriggerInstructionBufferLen = 128 + 1; // 128bytes is max UserActiveModeTriggerInstruction size and 1 byte is for escape sequence. + +constexpr uint8_t kCountryCodeBufferLen = 2; /** * This class contains all relevant information for the JNI view of CHIPDeviceController * to handle all controller-related processing. @@ -123,10 +125,7 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel chip::Credentials::PartialDACVerifier * GetPartialDACVerifier() { return &mPartialDACVerifier; } - const chip::Controller::CommissioningParameters & GetCommissioningParameters() const - { - return mAutoCommissioner.GetCommissioningParameters(); - } + const chip::Controller::CommissioningParameters & GetCommissioningParameters() const { return mCommissioningParameter; } static AndroidDeviceControllerWrapper * FromJNIHandle(jlong handle) { @@ -171,20 +170,19 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel * @param[in] skipCommissioningComplete whether to skip the CASE commissioningComplete command during commissioning * @param[out] errInfoOnFailure a pointer to a CHIP_ERROR that will be populated if this method returns nullptr */ - static AndroidDeviceControllerWrapper * - AllocateNew(JavaVM * vm, jobject deviceControllerObj, chip::NodeId nodeId, chip::FabricId fabricId, - const chip::CATValues & cats, chip::System::Layer * systemLayer, - chip::Inet::EndPointManager * tcpEndPointManager, - chip::Inet::EndPointManager * udpEndPointManager, + static AndroidDeviceControllerWrapper * AllocateNew( + JavaVM * vm, jobject deviceControllerObj, chip::NodeId nodeId, chip::FabricId fabricId, const chip::CATValues & cats, + chip::System::Layer * systemLayer, chip::Inet::EndPointManager * tcpEndPointManager, + chip::Inet::EndPointManager * udpEndPointManager, #ifdef JAVA_MATTER_CONTROLLER_TEST - ExampleOperationalCredentialsIssuerPtr opCredsIssuer, + ExampleOperationalCredentialsIssuerPtr opCredsIssuer, #else - AndroidOperationalCredentialsIssuerPtr opCredsIssuer, + AndroidOperationalCredentialsIssuerPtr opCredsIssuer, #endif - jobject keypairDelegate, jbyteArray rootCertificate, jbyteArray intermediateCertificate, - jbyteArray nodeOperationalCertificate, jbyteArray ipkEpochKey, uint16_t listenPort, uint16_t controllerVendorId, - uint16_t failsafeTimerSeconds, bool attemptNetworkScanWiFi, bool attemptNetworkScanThread, - bool skipCommissioningComplete, bool skipAttestationCertificateValidation, CHIP_ERROR * errInfoOnFailure); + jobject keypairDelegate, jbyteArray rootCertificate, jbyteArray intermediateCertificate, + jbyteArray nodeOperationalCertificate, jbyteArray ipkEpochKey, uint16_t listenPort, uint16_t controllerVendorId, + uint16_t failsafeTimerSeconds, bool attemptNetworkScanWiFi, bool attemptNetworkScanThread, bool skipCommissioningComplete, + bool skipAttestationCertificateValidation, jstring countryCode, CHIP_ERROR * errInfoOnFailure); void Shutdown(); @@ -246,6 +244,8 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel std::vector mIcacCertificate; std::vector mRcacCertificate; + char mCountryCode[kCountryCodeBufferLen]; + chip::Controller::AutoCommissioner mAutoCommissioner; chip::Credentials::PartialDACVerifier mPartialDACVerifier; @@ -262,6 +262,8 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel chip::MutableCharSpan mUserActiveModeTriggerInstruction = chip::MutableCharSpan(mUserActiveModeTriggerInstructionBuffer); chip::BitMask mUserActiveModeTriggerHint; + chip::Controller::CommissioningParameters mCommissioningParameter; + AndroidDeviceControllerWrapper(ChipDeviceControllerPtr controller, #ifdef JAVA_MATTER_CONTROLLER_TEST ExampleOperationalCredentialsIssuerPtr opCredsIssuer diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn index 21e667716bbcb2..ff42d1b43a42f4 100644 --- a/src/controller/java/BUILD.gn +++ b/src/controller/java/BUILD.gn @@ -396,7 +396,6 @@ kotlin_library("kotlin_matter_controller") { if (matter_enable_java_compilation) { deps += [ - "${chip_root}/third_party/java_deps:json", "${chip_root}/third_party/java_deps:kotlin-stdlib", "${chip_root}/third_party/java_deps:kotlinx-coroutines-core-jvm", "${chip_root}/third_party/java_deps/stub_src", @@ -451,6 +450,7 @@ android_library("java") { "src/chip/devicecontroller/ChipCommandType.java", "src/chip/devicecontroller/ChipDeviceController.java", "src/chip/devicecontroller/ChipDeviceControllerException.java", + "src/chip/devicecontroller/CommissioningWindowStatus.java", "src/chip/devicecontroller/ConnectionFailureException.java", "src/chip/devicecontroller/ControllerParams.java", "src/chip/devicecontroller/DeviceAttestationDelegate.java", @@ -470,6 +470,7 @@ android_library("java") { "src/chip/devicecontroller/OTAProviderDelegate.java", "src/chip/devicecontroller/OpenCommissioningCallback.java", "src/chip/devicecontroller/OperationalKeyConfig.java", + "src/chip/devicecontroller/PairingHintBitmap.java", "src/chip/devicecontroller/PaseVerifierParams.java", "src/chip/devicecontroller/ReportCallback.java", "src/chip/devicecontroller/ReportCallbackJni.java", diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp index fc2c0694b29849..f1c7487e4e3f87 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -371,6 +371,10 @@ JNI_METHOD(jlong, newDeviceController)(JNIEnv * env, jobject self, jobject contr jobject countryCodeOptional = env->CallObjectMethod(controllerParams, getCountryCode); jobject regulatoryLocationOptional = env->CallObjectMethod(controllerParams, getRegulatoryLocation); + jobject countryCode; + err = chip::JniReferences::GetInstance().GetOptionalValue(countryCodeOptional, countryCode); + SuccessOrExit(err); + #ifdef JAVA_MATTER_CONTROLLER_TEST std::unique_ptr opCredsIssuer( new chip::Controller::ExampleOperationalCredentialsIssuer()); @@ -383,7 +387,7 @@ JNI_METHOD(jlong, newDeviceController)(JNIEnv * env, jobject self, jobject contr DeviceLayer::TCPEndPointManager(), DeviceLayer::UDPEndPointManager(), std::move(opCredsIssuer), keypairDelegate, rootCertificate, intermediateCertificate, operationalCertificate, ipk, listenPort, controllerVendorId, failsafeTimerSeconds, attemptNetworkScanWiFi, attemptNetworkScanThread, skipCommissioningComplete, - skipAttestationCertificateValidation, &err); + skipAttestationCertificateValidation, static_cast(countryCode), &err); SuccessOrExit(err); if (caseFailsafeTimerSeconds > 0) @@ -411,29 +415,6 @@ JNI_METHOD(jlong, newDeviceController)(JNIEnv * env, jobject self, jobject contr } } - jobject countryCode; - err = chip::JniReferences::GetInstance().GetOptionalValue(countryCodeOptional, countryCode); - SuccessOrExit(err); - - if (countryCode != nullptr) - { - jstring countryCodeStr = static_cast(countryCode); - JniUtfString countryCodeJniString(env, countryCodeStr); - - VerifyOrExit(countryCodeJniString.size() == 2, err = CHIP_ERROR_INVALID_ARGUMENT); - - chip::Controller::CommissioningParameters commissioningParams = wrapper->GetCommissioningParameters(); - commissioningParams.SetCountryCode(countryCodeJniString.charSpan()); - - // The wrapper internally has reserved storage for the country code and will copy the value. - err = wrapper->UpdateCommissioningParameters(commissioningParams); - if (err != CHIP_NO_ERROR) - { - ChipLogError(Controller, "UpdateCommissioningParameters failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); - SuccessOrExit(err); - } - } - jobject regulatoryLocation; err = chip::JniReferences::GetInstance().GetOptionalValue(regulatoryLocationOptional, regulatoryLocation); SuccessOrExit(err); @@ -876,7 +857,7 @@ JNI_METHOD(void, updateCommissioningNetworkCredentials) chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); - CommissioningParameters commissioningParams = wrapper->GetCommissioningParameters(); + CommissioningParameters commissioningParams = wrapper->GetAutoCommissioner()->GetCommissioningParameters(); CHIP_ERROR err = wrapper->ApplyNetworkCredentials(commissioningParams, networkCredentials); if (err != CHIP_NO_ERROR) { @@ -884,10 +865,10 @@ JNI_METHOD(void, updateCommissioningNetworkCredentials) JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); return; } - err = wrapper->UpdateCommissioningParameters(commissioningParams); + err = wrapper->GetAutoCommissioner()->SetCommissioningParameters(commissioningParams); if (err != CHIP_NO_ERROR) { - ChipLogError(Controller, "UpdateCommissioningParameters failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); + ChipLogError(Controller, "SetCommissioningParameters failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); return; } @@ -911,7 +892,7 @@ JNI_METHOD(void, updateCommissioningICDRegistrationInfo) chip::DeviceLayer::StackLock lock; AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle); - CommissioningParameters commissioningParams = wrapper->GetCommissioningParameters(); + CommissioningParameters commissioningParams = wrapper->GetAutoCommissioner()->GetCommissioningParameters(); CHIP_ERROR err = wrapper->ApplyICDRegistrationInfo(commissioningParams, icdRegistrationInfo); if (err != CHIP_NO_ERROR) { @@ -919,10 +900,10 @@ JNI_METHOD(void, updateCommissioningICDRegistrationInfo) JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); return; } - err = wrapper->UpdateCommissioningParameters(commissioningParams); + err = wrapper->GetAutoCommissioner()->SetCommissioningParameters(commissioningParams); if (err != CHIP_NO_ERROR) { - ChipLogError(Controller, "UpdateCommissioningParameters failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); + ChipLogError(Controller, "SetCommissioningParameters failed. Err = %" CHIP_ERROR_FORMAT, err.Format()); JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); return; } @@ -1897,9 +1878,19 @@ JNI_METHOD(jobject, getDiscoveredDevice)(JNIEnv * env, jobject self, jlong handl jclass discoveredDeviceCls = env->FindClass("chip/devicecontroller/DiscoveredDevice"); jmethodID constructor = env->GetMethodID(discoveredDeviceCls, "", "()V"); - jfieldID discrminatorID = env->GetFieldID(discoveredDeviceCls, "discriminator", "J"); - jfieldID ipAddressID = env->GetFieldID(discoveredDeviceCls, "ipAddress", "Ljava/lang/String;"); - jfieldID portID = env->GetFieldID(discoveredDeviceCls, "port", "I"); + jfieldID discrminatorID = env->GetFieldID(discoveredDeviceCls, "discriminator", "J"); + jfieldID ipAddressID = env->GetFieldID(discoveredDeviceCls, "ipAddress", "Ljava/lang/String;"); + jfieldID portID = env->GetFieldID(discoveredDeviceCls, "port", "I"); + jfieldID deviceTypeID = env->GetFieldID(discoveredDeviceCls, "deviceType", "J"); + jfieldID vendorIdID = env->GetFieldID(discoveredDeviceCls, "vendorId", "I"); + jfieldID productIdID = env->GetFieldID(discoveredDeviceCls, "productId", "I"); + jfieldID rotatingIdID = env->GetFieldID(discoveredDeviceCls, "rotatingId", "[B"); + jfieldID instanceNameID = env->GetFieldID(discoveredDeviceCls, "instanceName", "Ljava/lang/String;"); + jfieldID deviceNameID = env->GetFieldID(discoveredDeviceCls, "deviceName", "Ljava/lang/String;"); + jfieldID pairingInstructionID = env->GetFieldID(discoveredDeviceCls, "pairingInstruction", "Ljava/lang/String;"); + + jmethodID setCommissioningModeID = env->GetMethodID(discoveredDeviceCls, "setCommissioningMode", "(I)V"); + jmethodID setPairingHintID = env->GetMethodID(discoveredDeviceCls, "setPairingHint", "(I)V"); jobject discoveredObj = env->NewObject(discoveredDeviceCls, constructor); @@ -1911,6 +1902,26 @@ JNI_METHOD(jobject, getDiscoveredDevice)(JNIEnv * env, jobject self, jlong handl env->SetObjectField(discoveredObj, ipAddressID, jniipAdress); env->SetIntField(discoveredObj, portID, static_cast(data->resolutionData.port)); + env->SetLongField(discoveredObj, deviceTypeID, static_cast(data->commissionData.deviceType)); + env->SetIntField(discoveredObj, vendorIdID, static_cast(data->commissionData.vendorId)); + env->SetIntField(discoveredObj, productIdID, static_cast(data->commissionData.productId)); + + jbyteArray jRotatingId; + CHIP_ERROR err = JniReferences::GetInstance().N2J_ByteArray( + env, data->commissionData.rotatingId, static_cast(data->commissionData.rotatingIdLen), jRotatingId); + + if (err != CHIP_NO_ERROR) + { + ChipLogError(Controller, "jRotatingId N2J_ByteArray error : %" CHIP_ERROR_FORMAT, err.Format()); + return nullptr; + } + env->SetObjectField(discoveredObj, rotatingIdID, static_cast(jRotatingId)); + env->SetObjectField(discoveredObj, instanceNameID, env->NewStringUTF(data->commissionData.instanceName)); + env->SetObjectField(discoveredObj, deviceNameID, env->NewStringUTF(data->commissionData.deviceName)); + env->SetObjectField(discoveredObj, pairingInstructionID, env->NewStringUTF(data->commissionData.pairingInstruction)); + + env->CallVoidMethod(discoveredObj, setCommissioningModeID, static_cast(data->commissionData.commissioningMode)); + env->CallVoidMethod(discoveredObj, setPairingHintID, static_cast(data->commissionData.pairingHint)); return discoveredObj; } diff --git a/src/controller/java/src/chip/devicecontroller/CommissioningWindowStatus.java b/src/controller/java/src/chip/devicecontroller/CommissioningWindowStatus.java new file mode 100644 index 00000000000000..bfced35f778b78 --- /dev/null +++ b/src/controller/java/src/chip/devicecontroller/CommissioningWindowStatus.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package chip.devicecontroller; + +public enum CommissioningWindowStatus { + WindowNotOpen(0), + EnhancedWindowOpen(1), + BasicWindowOpen(2); + + private final int value; + + CommissioningWindowStatus(int value) { + this.value = value; + } + + public static CommissioningWindowStatus value(int value) { + for (CommissioningWindowStatus status : CommissioningWindowStatus.values()) { + if (status.value == value) { + return status; + } + } + throw new IllegalArgumentException("Invalid value: " + value); + } +} diff --git a/src/controller/java/src/chip/devicecontroller/DiscoveredDevice.java b/src/controller/java/src/chip/devicecontroller/DiscoveredDevice.java index 01d6ecc28cce42..2fb8bcf4e79842 100644 --- a/src/controller/java/src/chip/devicecontroller/DiscoveredDevice.java +++ b/src/controller/java/src/chip/devicecontroller/DiscoveredDevice.java @@ -17,8 +17,66 @@ */ package chip.devicecontroller; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + public class DiscoveredDevice { public long discriminator; public String ipAddress; public int port; + public long deviceType; + public int vendorId; + public int productId; + public Set pairingHint; + public CommissioningWindowStatus commissioningMode; + public byte[] rotatingId; + public String instanceName; + public String deviceName; + public String pairingInstruction; + + // For use in JNI. + private void setCommissioningMode(int value) { + this.commissioningMode = CommissioningWindowStatus.value(value); + } + + private void setPairingHint(int value) { + this.pairingHint = new HashSet<>(); + for (PairingHintBitmap mode : PairingHintBitmap.values()) { + int bitmask = 1 << mode.getBitIndex(); + if ((value & bitmask) != 0) { + pairingHint.add(mode); + } + } + } + + @Override + public String toString() { + return "DiscoveredDevice : {" + + "\n\tdiscriminator : " + + discriminator + + "\n\tipAddress : " + + ipAddress + + "\n\tport : " + + port + + "\n\tdeviceType : " + + deviceType + + "\n\tvendorId : " + + vendorId + + "\n\tproductId : " + + productId + + "\n\tpairingHint : " + + pairingHint + + "\n\tcommissioningMode : " + + commissioningMode + + "\n\trotatingId : " + + (rotatingId != null ? Arrays.toString(rotatingId) : "null") + + "\n\tinstanceName : " + + instanceName + + "\n\tdeviceName : " + + deviceName + + "\n\tpairingInstruction : " + + pairingInstruction + + "\n}"; + } } diff --git a/src/controller/java/src/chip/devicecontroller/PairingHintBitmap.java b/src/controller/java/src/chip/devicecontroller/PairingHintBitmap.java new file mode 100644 index 00000000000000..d13b710c9c1b98 --- /dev/null +++ b/src/controller/java/src/chip/devicecontroller/PairingHintBitmap.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package chip.devicecontroller; + +public enum PairingHintBitmap { + PowerCycle(0, false), + DeviceManufacturerURL(1, false), + Administrator(2, false), + SettingsMenuOnTheNode(3, false), + CustomInstruction(4, true), + DeviceManual(5, false), + PressResetButton(6, false), + PressResetButtonWithApplicationOfPower(7, false), + PressResetButtonForNseconds(8, true), + PressResetButtonUntilLightBlinks(9, true), + PressResetButtonForNsecondsWithApplicationOfPower(10, true), + PressResetButtonUntilLightBlinksWithApplicationOfPower(11, true), + PressResetButtonNTimes(12, true), + PressSetupButton(13, false), + PressSetupButtonWithApplicationOfPower(14, false), + PressSetupButtonForNseconds(15, true), + PressSetupButtonUntilLightBlinks(16, true), + PressSetupButtonForNsecondsWithApplicationOfPower(17, true), + PressSetupButtonUntilLightBlinksWithApplicationOfPower(18, true), + PressSetupButtonNtimes(19, true); + + private final int bitIndex; + private final boolean isRequirePairingInstruction; + + PairingHintBitmap(int bitIndex, boolean isRequirePairingInstruction) { + this.bitIndex = bitIndex; + this.isRequirePairingInstruction = isRequirePairingInstruction; + } + + public int getBitIndex() { + return bitIndex; + } + + public boolean getRequirePairingInstruction() { + return isRequirePairingInstruction; + } +} diff --git a/src/darwin/Framework/CHIP/templates/availability.yaml b/src/darwin/Framework/CHIP/templates/availability.yaml index 91191285701e33..b745709fa434cf 100644 --- a/src/darwin/Framework/CHIP/templates/availability.yaml +++ b/src/darwin/Framework/CHIP/templates/availability.yaml @@ -7488,9 +7488,6 @@ Scenes: # New scenes bits not stable yet. - SceneTableSize - FanControl: - # New Fan Control bits not stable yet. - - AirflowDirection RVCCleanMode: # People are trying to deprecate this one - OnMode @@ -7498,9 +7495,6 @@ # People are trying to deprecate this one - OnMode commands: - FanControl: - # Not stable yet - - Step DoorLock: # Not stable yet - UnboltDoor @@ -7508,11 +7502,6 @@ # Disallowed in the spec, but present in our XML? - Start - Stop - enums: - FanControl: - # Not stable yet. - - StepDirectionEnum - - AirflowDirectionEnum enum values: DoorLock: # Not stable yet @@ -7544,11 +7533,6 @@ # here. Feature: - Unbolt - FanControl: - # Not stable yet - Feature: - - Step - - AirflowDirection RVCRunMode: Feature: # People are trying to deprecate this one @@ -8543,6 +8527,36 @@ - release: "Future" versions: "future" + introduced: + attributes: + FanControl: + - AirflowDirection + commands: + FanControl: + - Step + command fields: + FanControl: + Step: + - direction + - wrap + - lowestOff + enums: + FanControl: + - StepDirectionEnum + - AirflowDirectionEnum + enum values: + FanControl: + StepDirectionEnum: + - Increase + - Decrease + AirflowDirectionEnum: + - Forward + - Reverse + bitmap values: + FanControl: + Feature: + - Step + - AirflowDirection provisional: clusters: # Targeting Spring 2024 Matter release diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h index 6232b6424b8eb1..d28558722a280f 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h @@ -10202,7 +10202,7 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) * * The Step command speeds up or slows down the fan, in steps. */ -- (void)stepWithParams:(MTRFanControlClusterStepParams *)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; +- (void)stepWithParams:(MTRFanControlClusterStepParams *)params completion:(MTRStatusCompletion)completion MTR_NEWLY_AVAILABLE; - (void)readAttributeFanModeWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); - (void)writeAttributeFanModeWithValue:(NSNumber * _Nonnull)value completion:(MTRStatusCompletion)completion MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); @@ -10282,13 +10282,13 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); + (void)readAttributeWindSettingWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); -- (void)readAttributeAirflowDirectionWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)writeAttributeAirflowDirectionWithValue:(NSNumber * _Nonnull)value completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; -- (void)writeAttributeAirflowDirectionWithValue:(NSNumber * _Nonnull)value params:(MTRWriteParams * _Nullable)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; +- (void)readAttributeAirflowDirectionWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_NEWLY_AVAILABLE; +- (void)writeAttributeAirflowDirectionWithValue:(NSNumber * _Nonnull)value completion:(MTRStatusCompletion)completion MTR_NEWLY_AVAILABLE; +- (void)writeAttributeAirflowDirectionWithValue:(NSNumber * _Nonnull)value params:(MTRWriteParams * _Nullable)params completion:(MTRStatusCompletion)completion MTR_NEWLY_AVAILABLE; - (void)subscribeAttributeAirflowDirectionWithParams:(MTRSubscribeParams *)params subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished - reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; -+ (void)readAttributeAirflowDirectionWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_NEWLY_AVAILABLE; ++ (void)readAttributeAirflowDirectionWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_NEWLY_AVAILABLE; - (void)readAttributeGeneratedCommandListWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); - (void)subscribeAttributeGeneratedCommandListWithParams:(MTRSubscribeParams *)params @@ -18935,9 +18935,9 @@ typedef NS_OPTIONS(uint8_t, MTRThermostatTemperatureSetpointHoldPolicyBitmap) { } MTR_PROVISIONALLY_AVAILABLE; typedef NS_ENUM(uint8_t, MTRFanControlAirflowDirection) { - MTRFanControlAirflowDirectionForward MTR_PROVISIONALLY_AVAILABLE = 0x00, - MTRFanControlAirflowDirectionReverse MTR_PROVISIONALLY_AVAILABLE = 0x01, -} MTR_PROVISIONALLY_AVAILABLE; + MTRFanControlAirflowDirectionForward MTR_NEWLY_AVAILABLE = 0x00, + MTRFanControlAirflowDirectionReverse MTR_NEWLY_AVAILABLE = 0x01, +} MTR_NEWLY_AVAILABLE; typedef NS_ENUM(uint8_t, MTRFanControlFanMode) { MTRFanControlFanModeOff MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) = 0x00, @@ -18980,17 +18980,17 @@ typedef NS_ENUM(uint8_t, MTRFanControlFanModeSequenceType) { } MTR_DEPRECATED("Please use MTRFanControlFanModeSequence", ios(16.1, 17.0), macos(13.0, 14.0), watchos(9.1, 10.0), tvos(16.1, 17.0)); typedef NS_ENUM(uint8_t, MTRFanControlStepDirection) { - MTRFanControlStepDirectionIncrease MTR_PROVISIONALLY_AVAILABLE = 0x00, - MTRFanControlStepDirectionDecrease MTR_PROVISIONALLY_AVAILABLE = 0x01, -} MTR_PROVISIONALLY_AVAILABLE; + MTRFanControlStepDirectionIncrease MTR_NEWLY_AVAILABLE = 0x00, + MTRFanControlStepDirectionDecrease MTR_NEWLY_AVAILABLE = 0x01, +} MTR_NEWLY_AVAILABLE; typedef NS_OPTIONS(uint32_t, MTRFanControlFeature) { MTRFanControlFeatureMultiSpeed MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) = 0x1, MTRFanControlFeatureAuto MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) = 0x2, MTRFanControlFeatureRocking MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) = 0x4, MTRFanControlFeatureWind MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) = 0x8, - MTRFanControlFeatureStep MTR_PROVISIONALLY_AVAILABLE = 0x10, - MTRFanControlFeatureAirflowDirection MTR_PROVISIONALLY_AVAILABLE = 0x20, + MTRFanControlFeatureStep MTR_NEWLY_AVAILABLE = 0x10, + MTRFanControlFeatureAirflowDirection MTR_NEWLY_AVAILABLE = 0x20, } MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); typedef NS_OPTIONS(uint8_t, MTRFanControlRockBitmap) { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h index a3351bc74d12d1..00d597ee594fd1 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h @@ -3510,7 +3510,7 @@ typedef NS_ENUM(uint32_t, MTRAttributeIDType) { MTRAttributeIDTypeClusterFanControlAttributeRockSettingID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x00000008, MTRAttributeIDTypeClusterFanControlAttributeWindSupportID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x00000009, MTRAttributeIDTypeClusterFanControlAttributeWindSettingID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x0000000A, - MTRAttributeIDTypeClusterFanControlAttributeAirflowDirectionID MTR_PROVISIONALLY_AVAILABLE = 0x0000000B, + MTRAttributeIDTypeClusterFanControlAttributeAirflowDirectionID MTR_NEWLY_AVAILABLE = 0x0000000B, MTRAttributeIDTypeClusterFanControlAttributeGeneratedCommandListID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = MTRAttributeIDTypeGlobalAttributeGeneratedCommandListID, MTRAttributeIDTypeClusterFanControlAttributeAcceptedCommandListID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = MTRAttributeIDTypeGlobalAttributeAcceptedCommandListID, MTRAttributeIDTypeClusterFanControlAttributeEventListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeEventListID, @@ -6493,7 +6493,7 @@ typedef NS_ENUM(uint32_t, MTRCommandIDType) { // Cluster FanControl deprecated command id names // Cluster FanControl commands - MTRCommandIDTypeClusterFanControlCommandStepID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, + MTRCommandIDTypeClusterFanControlCommandStepID MTR_NEWLY_AVAILABLE = 0x00000000, // Cluster ColorControl deprecated command id names MTRClusterColorControlCommandMoveToHueID diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h index 7ce97cfe09442f..0805d773d372df 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h @@ -4716,7 +4716,7 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @interface MTRClusterFanControl : MTRGenericCluster -- (void)stepWithParams:(MTRFanControlClusterStepParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; +- (void)stepWithParams:(MTRFanControlClusterStepParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion MTR_NEWLY_AVAILABLE; - (NSDictionary * _Nullable)readAttributeFanModeWithParams:(MTRReadParams * _Nullable)params MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); - (void)writeAttributeFanModeWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); @@ -4752,9 +4752,9 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) - (void)writeAttributeWindSettingWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); - (void)writeAttributeWindSettingWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs params:(MTRWriteParams * _Nullable)params MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); -- (NSDictionary * _Nullable)readAttributeAirflowDirectionWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; -- (void)writeAttributeAirflowDirectionWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs MTR_PROVISIONALLY_AVAILABLE; -- (void)writeAttributeAirflowDirectionWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs params:(MTRWriteParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; +- (NSDictionary * _Nullable)readAttributeAirflowDirectionWithParams:(MTRReadParams * _Nullable)params MTR_NEWLY_AVAILABLE; +- (void)writeAttributeAirflowDirectionWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs MTR_NEWLY_AVAILABLE; +- (void)writeAttributeAirflowDirectionWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs params:(MTRWriteParams * _Nullable)params MTR_NEWLY_AVAILABLE; - (NSDictionary * _Nullable)readAttributeGeneratedCommandListWithParams:(MTRReadParams * _Nullable)params MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h index ccd23b30f0aceb..2d00e6618716e5 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h @@ -7759,14 +7759,14 @@ MTR_PROVISIONALLY_AVAILABLE @property (nonatomic, copy, nullable) NSNumber * serverSideProcessingTimeout; @end -MTR_PROVISIONALLY_AVAILABLE +MTR_NEWLY_AVAILABLE @interface MTRFanControlClusterStepParams : NSObject -@property (nonatomic, copy) NSNumber * _Nonnull direction MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nonnull direction MTR_NEWLY_AVAILABLE; -@property (nonatomic, copy) NSNumber * _Nullable wrap MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nullable wrap MTR_NEWLY_AVAILABLE; -@property (nonatomic, copy) NSNumber * _Nullable lowestOff MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nullable lowestOff MTR_NEWLY_AVAILABLE; /** * Controls whether the command is a timed command (using Timed Invoke). * diff --git a/src/messaging/ReliableMessageProtocolConfig.cpp b/src/messaging/ReliableMessageProtocolConfig.cpp index d2cda6123af5cb..e635e91940e0ef 100644 --- a/src/messaging/ReliableMessageProtocolConfig.cpp +++ b/src/messaging/ReliableMessageProtocolConfig.cpp @@ -57,18 +57,44 @@ void ClearLocalMRPConfigOverride() } #endif +#if CHIP_DEVICE_CONFIG_ENABLE_DYNAMIC_MRP_CONFIG +namespace { + +// This is not a static member of ReliableMessageProtocolConfig because the free +// function GetLocalMRPConfig() needs access to it. +Optional sDynamicLocalMPRConfig; + +} // anonymous namespace + +bool ReliableMessageProtocolConfig::SetLocalMRPConfig(const Optional & localMRPConfig) +{ + auto oldConfig = GetLocalMRPConfig(); + sDynamicLocalMPRConfig = localMRPConfig; + return oldConfig != GetLocalMRPConfig(); +} +#endif // CHIP_DEVICE_CONFIG_ENABLE_DYNAMIC_MRP_CONFIG + ReliableMessageProtocolConfig GetDefaultMRPConfig() { // Default MRP intervals are defined in spec <4.12.8. Parameters and Constants> static constexpr const System::Clock::Milliseconds32 idleRetransTimeout = 500_ms32; static constexpr const System::Clock::Milliseconds32 activeRetransTimeout = 300_ms32; static constexpr const System::Clock::Milliseconds16 activeThresholdTime = 4000_ms16; + static_assert(activeThresholdTime == kDefaultActiveTime, "Different active defaults?"); return ReliableMessageProtocolConfig(idleRetransTimeout, activeRetransTimeout, activeThresholdTime); } Optional GetLocalMRPConfig() { ReliableMessageProtocolConfig config(CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL, CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL); + +#if CHIP_DEVICE_CONFIG_ENABLE_DYNAMIC_MRP_CONFIG + if (sDynamicLocalMPRConfig.HasValue()) + { + config = sDynamicLocalMPRConfig.Value(); + } +#endif // CHIP_DEVICE_CONFIG_ENABLE_DYNAMIC_MRP_CONFIG + #if CHIP_CONFIG_ENABLE_ICD_SERVER // TODO ICD LIT shall not advertise the SII key // Increase local MRP retry intervals by ICD polling intervals. That is, intervals for diff --git a/src/messaging/ReliableMessageProtocolConfig.h b/src/messaging/ReliableMessageProtocolConfig.h index 87864d1a67e922..2ab1c139657fc6 100644 --- a/src/messaging/ReliableMessageProtocolConfig.h +++ b/src/messaging/ReliableMessageProtocolConfig.h @@ -208,6 +208,29 @@ struct ReliableMessageProtocolConfig return mIdleRetransTimeout == that.mIdleRetransTimeout && mActiveRetransTimeout == that.mActiveRetransTimeout && mActiveThresholdTime == that.mActiveThresholdTime; } + +#if CHIP_DEVICE_CONFIG_ENABLE_DYNAMIC_MRP_CONFIG + /** + * Set the local MRP configuration for the node. + * + * Passing a "no value" optional resets to the compiled-in settings + * (CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL and + * CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL). + * + * Otherwise the value set via this function is used instead of the + * compiled-in settings, but can still be overridden by ICD configuration + * and other things that would override the compiled-in settings. + * + * Changing the value via this function does not affect any existing + * sessions or exchanges, but does affect the values we communicate to our + * peer during future session establishments. + * + * @return whether the local MRP configuration actually changed as a result + * of this call. If it did, callers may need to reset DNS-SD + * advertising to advertise the updated values. + */ + static bool SetLocalMRPConfig(const Optional & localMRPConfig); +#endif // CHIP_DEVICE_CONFIG_ENABLE_DYNAMIC_MRP_CONFIG }; /// @brief The default MRP config. The value is defined by spec, and shall be same for all implementations, diff --git a/src/platform/BUILD.gn b/src/platform/BUILD.gn index 3c1f56da771786..4a0760334fb8cb 100644 --- a/src/platform/BUILD.gn +++ b/src/platform/BUILD.gn @@ -80,6 +80,11 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { # Define the default number of ip addresses to discover chip_max_discovered_ip_addresses = 5 + + # Allows enabling dynamic setting of the local MRP configuration, for + # devices with multiple radios that have different sleep behavior for + # different radios. + chip_device_config_enable_dynamic_mrp_config = false } if (chip_stack_lock_tracking == "auto") { @@ -131,6 +136,7 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { "CHIP_DISABLE_PLATFORM_KVS=${chip_disable_platform_kvs}", "CHIP_USE_TRANSITIONAL_COMMISSIONABLE_DATA_PROVIDER=${chip_use_transitional_commissionable_data_provider}", "CHIP_USE_TRANSITIONAL_DEVICE_INSTANCE_INFO_PROVIDER=${chip_use_transitional_device_instance_info_provider}", + "CHIP_DEVICE_CONFIG_ENABLE_DYNAMIC_MRP_CONFIG=${chip_device_config_enable_dynamic_mrp_config}", ] if (chip_device_platform == "linux" || chip_device_platform == "darwin" || diff --git a/src/platform/GLibTypeDeleter.h b/src/platform/GLibTypeDeleter.h index f083a6c5e460d5..b1cec176ad4715 100644 --- a/src/platform/GLibTypeDeleter.h +++ b/src/platform/GLibTypeDeleter.h @@ -120,6 +120,12 @@ struct GAutoPtrDeleter using deleter = GObjectDeleter; }; +template <> +struct GAutoPtrDeleter +{ + using deleter = GObjectDeleter; +}; + template <> struct GAutoPtrDeleter { diff --git a/src/platform/Linux/bluez/AdapterIterator.cpp b/src/platform/Linux/bluez/AdapterIterator.cpp index 5510ceae996ce2..ced172446882b8 100644 --- a/src/platform/Linux/bluez/AdapterIterator.cpp +++ b/src/platform/Linux/bluez/AdapterIterator.cpp @@ -26,69 +26,38 @@ namespace chip { namespace DeviceLayer { namespace Internal { -AdapterIterator::~AdapterIterator() -{ - if (mManager != nullptr) - { - g_object_unref(mManager); - } - - if (mObjectList != nullptr) - { - g_list_free_full(mObjectList, g_object_unref); - } -} - -CHIP_ERROR AdapterIterator::Initialize(AdapterIterator * self) +CHIP_ERROR AdapterIterator::Initialize() { // When creating D-Bus proxy object, the thread default context must be initialized. Otherwise, // all D-Bus signals will be delivered to the GLib global default main context. VerifyOrDie(g_main_context_get_thread_default() != nullptr); - CHIP_ERROR err = CHIP_NO_ERROR; GAutoPtr error; - - self->mManager = g_dbus_object_manager_client_new_for_bus_sync( + mManager.reset(g_dbus_object_manager_client_new_for_bus_sync( G_BUS_TYPE_SYSTEM, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, BLUEZ_INTERFACE, "/", bluez_object_manager_client_get_proxy_type, nullptr /* unused user data in the Proxy Type Func */, - nullptr /* destroy notify */, nullptr /* cancellable */, &error.GetReceiver()); + nullptr /* destroy notify */, nullptr /* cancellable */, &error.GetReceiver())); - VerifyOrExit(self->mManager != nullptr, ChipLogError(DeviceLayer, "Failed to get DBUS object manager for listing adapters."); - err = CHIP_ERROR_INTERNAL); + VerifyOrReturnError(mManager, CHIP_ERROR_INTERNAL, + ChipLogError(DeviceLayer, "Failed to get D-Bus object manager for listing adapters: %s", error->message)); - self->mObjectList = g_dbus_object_manager_get_objects(self->mManager); - self->mCurrentListItem = self->mObjectList; + mObjectList.Init(mManager.get()); + mIterator = mObjectList.begin(); -exit: - if (error != nullptr) - { - ChipLogError(DeviceLayer, "DBus error: %s", error->message); - } - - return err; + return CHIP_NO_ERROR; } bool AdapterIterator::Advance() { - if (mCurrentListItem == nullptr) + for (; mIterator != BluezObjectList::end(); ++mIterator) { - return false; - } - - while (mCurrentListItem != nullptr) - { - BluezAdapter1 * adapter = bluez_object_get_adapter1(BLUEZ_OBJECT(mCurrentListItem->data)); - if (adapter == nullptr) + BluezAdapter1 * adapter = bluez_object_get_adapter1(&(*mIterator)); + if (adapter != nullptr) { - mCurrentListItem = mCurrentListItem->next; - continue; + mCurrentAdapter.reset(adapter); + ++mIterator; + return true; } - - mCurrentAdapter.reset(adapter); - - mCurrentListItem = mCurrentListItem->next; - - return true; } return false; @@ -112,9 +81,10 @@ uint32_t AdapterIterator::GetIndex() const bool AdapterIterator::Next() { - if (mManager == nullptr) + if (!mManager) { - CHIP_ERROR err = PlatformMgrImpl().GLibMatterContextInvokeSync(Initialize, this); + CHIP_ERROR err = PlatformMgrImpl().GLibMatterContextInvokeSync( + +[](AdapterIterator * self) { return self->Initialize(); }, this); VerifyOrReturnError(err == CHIP_NO_ERROR, false, ChipLogError(DeviceLayer, "Failed to initialize adapter iterator")); } diff --git a/src/platform/Linux/bluez/AdapterIterator.h b/src/platform/Linux/bluez/AdapterIterator.h index 0d44074889773b..38af64f7ecc21c 100644 --- a/src/platform/Linux/bluez/AdapterIterator.h +++ b/src/platform/Linux/bluez/AdapterIterator.h @@ -17,13 +17,15 @@ #pragma once -#include +#include #include #include +#include #include +#include "BluezObjectList.h" #include "Types.h" namespace chip { @@ -46,8 +48,6 @@ namespace Internal { class AdapterIterator { public: - ~AdapterIterator(); - /// Moves to the next DBUS interface. /// /// MUST be called before any of the 'current value' methods are @@ -65,7 +65,7 @@ class AdapterIterator private: /// Sets up the DBUS manager and loads the list - static CHIP_ERROR Initialize(AdapterIterator * self); + CHIP_ERROR Initialize(); /// Loads the next value in the list. /// @@ -73,9 +73,9 @@ class AdapterIterator /// iterate through. bool Advance(); - GDBusObjectManager * mManager = nullptr; // DBus connection - GList * mObjectList = nullptr; // listing of objects on the bus - GList * mCurrentListItem = nullptr; // current item viewed in the list + GAutoPtr mManager; + BluezObjectList mObjectList; + BluezObjectIterator mIterator; // Data valid only if Next() returns true GAutoPtr mCurrentAdapter; }; diff --git a/src/platform/Linux/bluez/BluezAdvertisement.cpp b/src/platform/Linux/bluez/BluezAdvertisement.cpp index 06f831bff8b58f..0fed99478cdaf9 100644 --- a/src/platform/Linux/bluez/BluezAdvertisement.cpp +++ b/src/platform/Linux/bluez/BluezAdvertisement.cpp @@ -224,7 +224,7 @@ void BluezAdvertisement::Shutdown() void BluezAdvertisement::StartDone(GObject * aObject, GAsyncResult * aResult) { - BluezLEAdvertisingManager1 * advMgr = BLUEZ_LEADVERTISING_MANAGER1(aObject); + auto * advMgr = reinterpret_cast(aObject); GAutoPtr error; gboolean success = FALSE; @@ -252,7 +252,7 @@ CHIP_ERROR BluezAdvertisement::StartImpl() adapterObject = g_dbus_interface_get_object(G_DBUS_INTERFACE(mAdapter.get())); VerifyOrExit(adapterObject != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapterObject in %s", __func__)); - advMgr.reset(bluez_object_get_leadvertising_manager1(BLUEZ_OBJECT(adapterObject))); + advMgr.reset(bluez_object_get_leadvertising_manager1(reinterpret_cast(adapterObject))); VerifyOrExit(advMgr.get() != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL advMgr in %s", __func__)); g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE("a{sv}")); @@ -282,7 +282,7 @@ CHIP_ERROR BluezAdvertisement::Start() void BluezAdvertisement::StopDone(GObject * aObject, GAsyncResult * aResult) { - BluezLEAdvertisingManager1 * advMgr = BLUEZ_LEADVERTISING_MANAGER1(aObject); + auto * advMgr = reinterpret_cast(aObject); GAutoPtr error; gboolean success = FALSE; @@ -308,7 +308,7 @@ CHIP_ERROR BluezAdvertisement::StopImpl() adapterObject = g_dbus_interface_get_object(G_DBUS_INTERFACE(mAdapter.get())); VerifyOrExit(adapterObject != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapterObject in %s", __func__)); - advMgr.reset(bluez_object_get_leadvertising_manager1(BLUEZ_OBJECT(adapterObject))); + advMgr.reset(bluez_object_get_leadvertising_manager1(reinterpret_cast(adapterObject))); VerifyOrExit(advMgr.get() != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL advMgr in %s", __func__)); bluez_leadvertising_manager1_call_unregister_advertisement( diff --git a/src/platform/Linux/bluez/BluezConnection.cpp b/src/platform/Linux/bluez/BluezConnection.cpp index d2db5edc005eba..dd4f9b108e2eb8 100644 --- a/src/platform/Linux/bluez/BluezConnection.cpp +++ b/src/platform/Linux/bluez/BluezConnection.cpp @@ -34,6 +34,7 @@ #include #include "BluezEndpoint.h" +#include "BluezObjectList.h" #include "Types.h" namespace chip { @@ -95,10 +96,6 @@ BluezConnection::ConnectionDataBundle::ConnectionDataBundle(const BluezConnectio CHIP_ERROR BluezConnection::Init(const BluezEndpoint & aEndpoint) { - // populate the service and the characteristics - GList * objects = nullptr; - GList * l; - if (!aEndpoint.mIsCentral) { mpService = reinterpret_cast(g_object_ref(aEndpoint.mpService)); @@ -107,11 +104,9 @@ CHIP_ERROR BluezConnection::Init(const BluezEndpoint & aEndpoint) } else { - objects = g_dbus_object_manager_get_objects(aEndpoint.mpObjMgr); - - for (l = objects; l != nullptr; l = l->next) + for (BluezObject & object : BluezObjectList(aEndpoint.mpObjMgr)) { - BluezGattService1 * service = bluez_object_get_gatt_service1(BLUEZ_OBJECT(l->data)); + BluezGattService1 * service = bluez_object_get_gatt_service1(&object); if (service != nullptr) { if ((BluezIsServiceOnDevice(service, mpDevice)) == TRUE && @@ -126,9 +121,9 @@ CHIP_ERROR BluezConnection::Init(const BluezEndpoint & aEndpoint) VerifyOrExit(mpService != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL service in %s", __func__)); - for (l = objects; l != nullptr; l = l->next) + for (BluezObject & object : BluezObjectList(aEndpoint.mpObjMgr)) { - BluezGattCharacteristic1 * char1 = bluez_object_get_gatt_characteristic1(BLUEZ_OBJECT(l->data)); + BluezGattCharacteristic1 * char1 = bluez_object_get_gatt_characteristic1(&object); if (char1 != nullptr) { if ((BluezIsCharOnService(char1, mpService) == TRUE) && @@ -164,8 +159,6 @@ CHIP_ERROR BluezConnection::Init(const BluezEndpoint & aEndpoint) } exit: - if (objects != nullptr) - g_list_free_full(objects, g_object_unref); return CHIP_NO_ERROR; } @@ -305,9 +298,10 @@ CHIP_ERROR BluezConnection::SendIndication(chip::System::PacketBufferHandle apBu void BluezConnection::SendWriteRequestDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection) { - BluezGattCharacteristic1 * c1 = BLUEZ_GATT_CHARACTERISTIC1(aObject); + auto * pC1 = reinterpret_cast(aObject); + GAutoPtr error; - gboolean success = bluez_gatt_characteristic1_call_write_value_finish(c1, aResult, &error.GetReceiver()); + gboolean success = bluez_gatt_characteristic1_call_write_value_finish(pC1, aResult, &error.GetReceiver()); VerifyOrReturn(success == TRUE, ChipLogError(DeviceLayer, "FAIL: SendWriteRequest : %s", error->message)); BLEManagerImpl::HandleWriteComplete(static_cast(apConnection)); @@ -354,9 +348,10 @@ void BluezConnection::OnCharacteristicChanged(GDBusProxy * aInterface, GVariant void BluezConnection::SubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection) { - BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject); + auto * pC2 = reinterpret_cast(aObject); + GAutoPtr error; - gboolean success = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &error.GetReceiver()); + gboolean success = bluez_gatt_characteristic1_call_write_value_finish(pC2, aResult, &error.GetReceiver()); VerifyOrReturn(success == TRUE, ChipLogError(DeviceLayer, "FAIL: SubscribeCharacteristic : %s", error->message)); @@ -365,13 +360,12 @@ void BluezConnection::SubscribeCharacteristicDone(GObject * aObject, GAsyncResul CHIP_ERROR BluezConnection::SubscribeCharacteristicImpl(BluezConnection * connection) { - BluezGattCharacteristic1 * c2 = nullptr; - VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__)); - c2 = BLUEZ_GATT_CHARACTERISTIC1(connection->mpC2); + BluezGattCharacteristic1 * pC2 = connection->mpC2; + VerifyOrExit(pC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__)); // Get notifications on the TX characteristic change (e.g. indication is received) - g_signal_connect(c2, "g-properties-changed", G_CALLBACK(OnCharacteristicChanged), connection); - bluez_gatt_characteristic1_call_start_notify(connection->mpC2, nullptr, SubscribeCharacteristicDone, connection); + g_signal_connect(pC2, "g-properties-changed", G_CALLBACK(OnCharacteristicChanged), connection); + bluez_gatt_characteristic1_call_start_notify(pC2, nullptr, SubscribeCharacteristicDone, connection); exit: return CHIP_NO_ERROR; @@ -386,22 +380,24 @@ CHIP_ERROR BluezConnection::SubscribeCharacteristic() void BluezConnection::UnsubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection) { - BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject); + auto * pC2 = reinterpret_cast(aObject); + GAutoPtr error; - gboolean success = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &error.GetReceiver()); + gboolean success = bluez_gatt_characteristic1_call_write_value_finish(pC2, aResult, &error.GetReceiver()); VerifyOrReturn(success == TRUE, ChipLogError(DeviceLayer, "FAIL: UnsubscribeCharacteristic : %s", error->message)); // Stop listening to the TX characteristic changes - g_signal_handlers_disconnect_by_data(c2, apConnection); + g_signal_handlers_disconnect_by_data(pC2, apConnection); BLEManagerImpl::HandleSubscribeOpComplete(static_cast(apConnection), false); } CHIP_ERROR BluezConnection::UnsubscribeCharacteristicImpl(BluezConnection * connection) { - VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__)); + BluezGattCharacteristic1 * pC2 = connection->mpC2; + VerifyOrExit(pC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__)); - bluez_gatt_characteristic1_call_stop_notify(connection->mpC2, nullptr, UnsubscribeCharacteristicDone, connection); + bluez_gatt_characteristic1_call_stop_notify(pC2, nullptr, UnsubscribeCharacteristicDone, connection); exit: return CHIP_NO_ERROR; diff --git a/src/platform/Linux/bluez/BluezEndpoint.cpp b/src/platform/Linux/bluez/BluezEndpoint.cpp index 2fdd1e1788af6b..fe7a5a25171f73 100644 --- a/src/platform/Linux/bluez/BluezEndpoint.cpp +++ b/src/platform/Linux/bluez/BluezEndpoint.cpp @@ -72,6 +72,7 @@ #include #include "BluezConnection.h" +#include "BluezObjectList.h" #include "Types.h" namespace chip { @@ -262,9 +263,8 @@ BluezGattCharacteristic1 * BluezEndpoint::CreateGattCharacteristic(BluezGattServ void BluezEndpoint::RegisterGattApplicationDone(GObject * aObject, GAsyncResult * aResult) { GAutoPtr error; - BluezGattManager1 * gattMgr = BLUEZ_GATT_MANAGER1(aObject); - - gboolean success = bluez_gatt_manager1_call_register_application_finish(gattMgr, aResult, &error.GetReceiver()); + gboolean success = bluez_gatt_manager1_call_register_application_finish(reinterpret_cast(aObject), aResult, + &error.GetReceiver()); VerifyOrReturn(success == TRUE, { ChipLogError(DeviceLayer, "FAIL: RegisterApplication : %s", error->message); @@ -287,7 +287,7 @@ CHIP_ERROR BluezEndpoint::RegisterGattApplicationImpl() adapterObject = g_dbus_interface_get_object(G_DBUS_INTERFACE(mAdapter.get())); VerifyOrExit(adapterObject != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapterObject in %s", __func__)); - gattMgr.reset(bluez_object_get_gatt_manager1(BLUEZ_OBJECT(adapterObject))); + gattMgr.reset(bluez_object_get_gatt_manager1(reinterpret_cast(adapterObject))); VerifyOrExit(gattMgr.get() != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL gattMgr in %s", __func__)); g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE("a{sv}")); @@ -383,7 +383,7 @@ void BluezEndpoint::BluezSignalOnObjectAdded(GDBusObjectManager * aManager, GDBu { // TODO: right now we do not handle addition/removal of adapters // Primary focus here is to handle addition of a device - GAutoPtr device(bluez_object_get_device1(BLUEZ_OBJECT(aObject))); + GAutoPtr device(bluez_object_get_device1(reinterpret_cast(aObject))); VerifyOrReturn(device.get() != nullptr); if (BluezIsDeviceOnAdapter(device.get(), mAdapter.get()) == TRUE) @@ -421,15 +421,14 @@ BluezGattService1 * BluezEndpoint::CreateGattService(const char * aUUID) return service; } -void BluezEndpoint::SetupAdapter() +CHIP_ERROR BluezEndpoint::SetupAdapter() { char expectedPath[32]; snprintf(expectedPath, sizeof(expectedPath), BLUEZ_PATH "/hci%u", mAdapterId); - GList * objects = g_dbus_object_manager_get_objects(mpObjMgr); - for (auto l = objects; l != nullptr && mAdapter.get() == nullptr; l = l->next) + for (BluezObject & object : BluezObjectList(mpObjMgr)) { - GAutoPtr adapter(bluez_object_get_adapter1(BLUEZ_OBJECT(l->data))); + GAutoPtr adapter(bluez_object_get_adapter1(&object)); if (adapter.get() != nullptr) { if (mpAdapterAddr == nullptr) // no adapter address provided, bind to the hci indicated by nodeid @@ -451,7 +450,7 @@ void BluezEndpoint::SetupAdapter() } } - VerifyOrExit(mAdapter.get() != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL mAdapter in %s", __func__)); + VerifyOrReturnError(mAdapter, CHIP_ERROR_INTERNAL, ChipLogError(DeviceLayer, "FAIL: NULL mAdapter in %s", __func__)); bluez_adapter1_set_powered(mAdapter.get(), TRUE); @@ -460,8 +459,7 @@ void BluezEndpoint::SetupAdapter() // and the flag is necessary to force using LE transport. bluez_adapter1_set_discoverable(mAdapter.get(), FALSE); -exit: - g_list_free_full(objects, g_object_unref); + return CHIP_NO_ERROR; } BluezConnection * BluezEndpoint::GetBluezConnection(const char * aPath) diff --git a/src/platform/Linux/bluez/BluezEndpoint.h b/src/platform/Linux/bluez/BluezEndpoint.h index d35cebdf6a6cfe..687f0002fe64b0 100644 --- a/src/platform/Linux/bluez/BluezEndpoint.h +++ b/src/platform/Linux/bluez/BluezEndpoint.h @@ -85,7 +85,7 @@ class BluezEndpoint private: CHIP_ERROR StartupEndpointBindings(); - void SetupAdapter(); + CHIP_ERROR SetupAdapter(); void SetupGattServer(GDBusConnection * aConn); void SetupGattService(); diff --git a/src/platform/Linux/bluez/BluezObjectIterator.h b/src/platform/Linux/bluez/BluezObjectIterator.h index ae5e01c6b9e34d..6b177acd03027b 100644 --- a/src/platform/Linux/bluez/BluezObjectIterator.h +++ b/src/platform/Linux/bluez/BluezObjectIterator.h @@ -17,6 +17,8 @@ #pragma once +#include + #include #include @@ -41,8 +43,8 @@ class BluezObjectIterator BluezObjectIterator() = default; explicit BluezObjectIterator(GList * position) : mPosition(position) {} - reference operator*() const { return *BLUEZ_OBJECT(mPosition->data); } - pointer operator->() const { return BLUEZ_OBJECT(mPosition->data); } + reference operator*() const { return *reinterpret_cast(mPosition->data); } + pointer operator->() const { return reinterpret_cast(mPosition->data); } bool operator==(const BluezObjectIterator & other) const { return mPosition == other.mPosition; } bool operator!=(const BluezObjectIterator & other) const { return mPosition != other.mPosition; } diff --git a/src/platform/Linux/bluez/BluezObjectList.h b/src/platform/Linux/bluez/BluezObjectList.h index ee7f6c001514e6..5831f07a3c6c85 100644 --- a/src/platform/Linux/bluez/BluezObjectList.h +++ b/src/platform/Linux/bluez/BluezObjectList.h @@ -35,27 +35,26 @@ namespace Internal { class BluezObjectList { public: - explicit BluezObjectList(GDBusObjectManager * manager) { Initialize(manager); } + BluezObjectList() = default; + explicit BluezObjectList(GDBusObjectManager * manager) { Init(manager); } - ~BluezObjectList() { g_list_free_full(mObjectList, g_object_unref); } - - BluezObjectIterator begin() const { return BluezObjectIterator(mObjectList); } - BluezObjectIterator end() const { return BluezObjectIterator(); } - -protected: - BluezObjectList() {} - - void Initialize(GDBusObjectManager * manager) + ~BluezObjectList() { - if (manager == nullptr) - { - ChipLogError(DeviceLayer, "Manager is NULL in %s", __func__); - return; - } + if (mObjectList != nullptr) + g_list_free_full(mObjectList, g_object_unref); + } + CHIP_ERROR Init(GDBusObjectManager * manager) + { + VerifyOrReturnError(manager != nullptr, CHIP_ERROR_INVALID_ARGUMENT, + ChipLogError(DeviceLayer, "Manager is NULL in %s", __func__)); mObjectList = g_dbus_object_manager_get_objects(manager); + return CHIP_NO_ERROR; } + BluezObjectIterator begin() const { return BluezObjectIterator(mObjectList); } + static BluezObjectIterator end() { return BluezObjectIterator(); } + private: GList * mObjectList = nullptr; }; diff --git a/src/platform/Linux/bluez/ChipDeviceScanner.cpp b/src/platform/Linux/bluez/ChipDeviceScanner.cpp index 0d248058c3d1a0..5523bf87dfdf66 100644 --- a/src/platform/Linux/bluez/ChipDeviceScanner.cpp +++ b/src/platform/Linux/bluez/ChipDeviceScanner.cpp @@ -215,7 +215,7 @@ CHIP_ERROR ChipDeviceScanner::MainLoopStopScan(ChipDeviceScanner * self) void ChipDeviceScanner::SignalObjectAdded(GDBusObjectManager * manager, GDBusObject * object, ChipDeviceScanner * self) { - GAutoPtr device(bluez_object_get_device1(BLUEZ_OBJECT(object))); + GAutoPtr device(bluez_object_get_device1(reinterpret_cast(object))); VerifyOrReturn(device.get() != nullptr); self->ReportDevice(*device.get()); @@ -225,7 +225,7 @@ void ChipDeviceScanner::SignalInterfaceChanged(GDBusObjectManagerClient * manage GDBusProxy * aInterface, GVariant * aChangedProperties, const gchar * const * aInvalidatedProps, ChipDeviceScanner * self) { - GAutoPtr device(bluez_object_get_device1(BLUEZ_OBJECT(object))); + GAutoPtr device(bluez_object_get_device1(reinterpret_cast(object))); VerifyOrReturn(device.get() != nullptr); self->ReportDevice(*device.get()); diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp index 21c44dd00279e3..707e1f710743ec 100644 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp @@ -149,6 +149,7 @@ void GenericThreadStackManagerImpl_OpenThread::_ProcessThreadActivity template bool GenericThreadStackManagerImpl_OpenThread::_HaveRouteToAddress(const Inet::IPAddress & destAddr) { + VerifyOrReturnValue(mOTInst, false); bool res = false; // Lock OpenThread @@ -233,6 +234,7 @@ void GenericThreadStackManagerImpl_OpenThread::_OnPlatformEvent(const template bool GenericThreadStackManagerImpl_OpenThread::_IsThreadEnabled(void) { + VerifyOrReturnValue(mOTInst, false); otDeviceRole curRole; Impl()->LockThreadStack(); @@ -245,6 +247,7 @@ bool GenericThreadStackManagerImpl_OpenThread::_IsThreadEnabled(void) template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_SetThreadEnabled(bool val) { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); otError otErr = OT_ERROR_NONE; Impl()->LockThreadStack(); @@ -279,6 +282,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_SetThreadEnable template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_SetThreadProvision(ByteSpan netInfo) { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); otError otErr = OT_ERROR_FAILED; otOperationalDatasetTlvs tlvs; @@ -305,6 +309,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_SetThreadProvis template bool GenericThreadStackManagerImpl_OpenThread::_IsThreadProvisioned(void) { + VerifyOrReturnValue(mOTInst, false); bool provisioned; Impl()->LockThreadStack(); @@ -317,6 +322,7 @@ bool GenericThreadStackManagerImpl_OpenThread::_IsThreadProvisioned(v template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetThreadProvision(Thread::OperationalDataset & dataset) { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(Impl()->IsThreadProvisioned(), CHIP_ERROR_INCORRECT_STATE); otOperationalDatasetTlvs datasetTlv; @@ -336,6 +342,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetThreadProvis template bool GenericThreadStackManagerImpl_OpenThread::_IsThreadAttached(void) { + VerifyOrReturnValue(mOTInst, false); otDeviceRole curRole; Impl()->LockThreadStack(); @@ -380,6 +387,7 @@ template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_StartThreadScan(NetworkCommissioning::ThreadDriver::ScanCallback * callback) { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR error = CHIP_NO_ERROR; #if CHIP_CONFIG_ENABLE_ICD_SERVER otLinkModeConfig linkMode; @@ -488,6 +496,7 @@ void GenericThreadStackManagerImpl_OpenThread::_OnNetworkScanFinished template ConnectivityManager::ThreadDeviceType GenericThreadStackManagerImpl_OpenThread::_GetThreadDeviceType(void) { + VerifyOrReturnValue(mOTInst, ConnectivityManager::kThreadDeviceType_NotSupported); ConnectivityManager::ThreadDeviceType deviceType; Impl()->LockThreadStack(); @@ -524,6 +533,7 @@ template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_SetThreadDeviceType(ConnectivityManager::ThreadDeviceType deviceType) { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR err = CHIP_NO_ERROR; otLinkModeConfig linkMode; @@ -612,6 +622,7 @@ GenericThreadStackManagerImpl_OpenThread::_SetThreadDeviceType(Connec template bool GenericThreadStackManagerImpl_OpenThread::_HaveMeshConnectivity(void) { + VerifyOrReturnValue(mOTInst, false); bool res; otDeviceRole curRole; @@ -660,6 +671,7 @@ bool GenericThreadStackManagerImpl_OpenThread::_HaveMeshConnectivity( template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetAndLogThreadStatsCounters(void) { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR err = CHIP_NO_ERROR; otError otErr; otOperationalDataset activeDataset; @@ -754,6 +766,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetAndLogThread template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetAndLogThreadTopologyMinimal(void) { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR err = CHIP_NO_ERROR; #if CHIP_PROGRESS_LOGGING @@ -822,6 +835,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetAndLogThread template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetAndLogThreadTopologyFull() { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR err = CHIP_NO_ERROR; #if CHIP_PROGRESS_LOGGING @@ -991,6 +1005,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetAndLogThread template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetPrimary802154MACAddress(uint8_t * buf) { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); const otExtAddress * extendedAddr = otLinkGetExtendedAddress(mOTInst); memcpy(buf, extendedAddr, sizeof(otExtAddress)); return CHIP_NO_ERROR; @@ -999,6 +1014,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetPrimary80215 template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetExternalIPv6Address(chip::Inet::IPAddress & addr) { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); const otNetifAddress * otAddresses = otIp6GetUnicastAddresses(mOTInst); // Look only for the global unicast addresses, not internally assigned by Thread. @@ -1034,6 +1050,7 @@ void GenericThreadStackManagerImpl_OpenThread::_ResetThreadNetworkDia template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetPollPeriod(uint32_t & buf) { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); Impl()->LockThreadStack(); buf = otLinkGetPollPeriod(mOTInst); Impl()->UnlockThreadStack(); @@ -1121,6 +1138,7 @@ bool GenericThreadStackManagerImpl_OpenThread::IsThreadInterfaceUpNoL template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_SetPollingInterval(System::Clock::Milliseconds32 pollingInterval) { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR err = CHIP_NO_ERROR; Impl()->LockThreadStack(); @@ -1173,6 +1191,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_SetPollingInter template void GenericThreadStackManagerImpl_OpenThread::_ErasePersistentInfo(void) { + VerifyOrReturn(mOTInst); ChipLogProgress(DeviceLayer, "Erasing Thread persistent info..."); Impl()->LockThreadStack(); otThreadSetEnabled(mOTInst, false); @@ -1205,6 +1224,7 @@ void GenericThreadStackManagerImpl_OpenThread::OnJoinerComplete(otErr template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_JoinerStart(void) { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR error = CHIP_NO_ERROR; Impl()->LockThreadStack(); @@ -1254,6 +1274,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_JoinerStart(voi template void GenericThreadStackManagerImpl_OpenThread::_UpdateNetworkStatus() { + VerifyOrReturn(mOTInst); // Thread is not enabled, then we are not trying to connect to the network. VerifyOrReturn(ThreadStackMgrImpl().IsThreadEnabled() && mpStatusChangeCallback != nullptr); @@ -1636,6 +1657,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_RemoveInvalidSr template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_ClearAllSrpHostAndServices() { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR error = CHIP_NO_ERROR; Impl()->LockThreadStack(); if (!mIsSrpClearAllRequested) @@ -1684,6 +1706,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_SetupSrpHost(co template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_ClearSrpHost(const char * aHostName) { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR error = CHIP_NO_ERROR; Impl()->LockThreadStack(); @@ -1798,6 +1821,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::FromOtDnsRespons template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::ResolveAddress(intptr_t context, otDnsAddressCallback callback) { + VerifyOrReturnError(ThreadStackMgrImpl().OTInstance(), CHIP_ERROR_INCORRECT_STATE); DnsResult * dnsResult = reinterpret_cast(context); ThreadStackMgrImpl().LockThreadStack(); @@ -1952,6 +1976,7 @@ template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_DnsBrowse(const char * aServiceName, DnsBrowseCallback aCallback, void * aContext) { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR error = CHIP_NO_ERROR; Impl()->LockThreadStack(); @@ -2062,6 +2087,7 @@ template CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_DnsResolve(const char * aServiceName, const char * aInstanceName, DnsResolveCallback aCallback, void * aContext) { + VerifyOrReturnError(mOTInst, CHIP_ERROR_INCORRECT_STATE); CHIP_ERROR error = CHIP_NO_ERROR; Impl()->LockThreadStack(); diff --git a/src/platform/Zephyr/BLEManagerImpl.cpp b/src/platform/Zephyr/BLEManagerImpl.cpp index 09ddd4fbe34304..07f30dc0632a6c 100644 --- a/src/platform/Zephyr/BLEManagerImpl.cpp +++ b/src/platform/Zephyr/BLEManagerImpl.cpp @@ -39,6 +39,7 @@ #include #include +#include #include #include #include diff --git a/src/protocols/secure_channel/CASEServer.cpp b/src/protocols/secure_channel/CASEServer.cpp index 2ad196a31b9461..df0984d4d94eee 100644 --- a/src/protocols/secure_channel/CASEServer.cpp +++ b/src/protocols/secure_channel/CASEServer.cpp @@ -90,9 +90,31 @@ CHIP_ERROR CASEServer::OnMessageReceived(Messaging::ExchangeContext * ec, const // Handshake wasn't stuck, send the busy status report and let the existing handshake continue. // A successful CASE handshake can take several seconds and some may time out (30 seconds or more). - // TODO: Come up with better estimate: https://github.com/project-chip/connectedhomeip/issues/28288 - // For now, setting minimum wait time to 5000 milliseconds. - CHIP_ERROR err = SendBusyStatusReport(ec, System::Clock::Milliseconds16(5000)); + + System::Clock::Milliseconds16 delay = System::Clock::kZero; + if (GetSession().GetState() == CASESession::State::kSentSigma2) + { + // The delay should be however long we think it will take for + // that to time out. + auto sigma2Timeout = CASESession::ComputeSigma2ResponseTimeout(GetSession().GetRemoteMRPConfig()); + if (sigma2Timeout < System::Clock::Milliseconds16::max()) + { + delay = std::chrono::duration_cast(sigma2Timeout); + } + else + { + // Avoid overflow issues, just wait for as long as we can to + // get close to our expected Sigma2 timeout. + delay = System::Clock::Milliseconds16::max(); + } + } + else + { + // For now, setting minimum wait time to 5000 milliseconds if we + // have no other information. + delay = System::Clock::Milliseconds16(5000); + } + CHIP_ERROR err = SendBusyStatusReport(ec, delay); if (err != CHIP_NO_ERROR) { ChipLogError(Inet, "Failed to send the busy status report, err:%" CHIP_ERROR_FORMAT, err.Format()); diff --git a/src/protocols/secure_channel/CASESession.cpp b/src/protocols/secure_channel/CASESession.cpp index 30d1f71cb0ff64..a9b62489783794 100644 --- a/src/protocols/secure_channel/CASESession.cpp +++ b/src/protocols/secure_channel/CASESession.cpp @@ -1966,7 +1966,8 @@ void CASESession::OnSuccessStatusReport() Finish(); } -CHIP_ERROR CASESession::OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode) +CHIP_ERROR CASESession::OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode, + Optional protocolData) { CHIP_ERROR err = CHIP_NO_ERROR; switch (protocolCode) @@ -1981,6 +1982,10 @@ CHIP_ERROR CASESession::OnFailureStatusReport(Protocols::SecureChannel::GeneralS case kProtocolCodeBusy: err = CHIP_ERROR_BUSY; + if (protocolData.HasValue()) + { + mDelegate->OnResponderBusy(System::Clock::Milliseconds16(static_cast(protocolData.Value()))); + } break; default: diff --git a/src/protocols/secure_channel/CASESession.h b/src/protocols/secure_channel/CASESession.h index cb7f3c7f13380d..9e41f6c69fbe84 100644 --- a/src/protocols/secure_channel/CASESession.h +++ b/src/protocols/secure_channel/CASESession.h @@ -272,7 +272,8 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler, const ByteSpan & skInfo, const ByteSpan & nonce); void OnSuccessStatusReport() override; - CHIP_ERROR OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode) override; + CHIP_ERROR OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode, + Optional protocolData) override; void AbortPendingEstablish(CHIP_ERROR err); diff --git a/src/protocols/secure_channel/PASESession.cpp b/src/protocols/secure_channel/PASESession.cpp index 50b186100841e0..40dc67793604e2 100644 --- a/src/protocols/secure_channel/PASESession.cpp +++ b/src/protocols/secure_channel/PASESession.cpp @@ -759,7 +759,8 @@ void PASESession::OnSuccessStatusReport() Finish(); } -CHIP_ERROR PASESession::OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode) +CHIP_ERROR PASESession::OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode, + Optional protocolData) { CHIP_ERROR err = CHIP_NO_ERROR; switch (protocolCode) diff --git a/src/protocols/secure_channel/PASESession.h b/src/protocols/secure_channel/PASESession.h index 393d3a65fc958a..e270baf42e80f1 100644 --- a/src/protocols/secure_channel/PASESession.h +++ b/src/protocols/secure_channel/PASESession.h @@ -203,7 +203,8 @@ class DLL_EXPORT PASESession : public Messaging::UnsolicitedMessageHandler, CHIP_ERROR HandleMsg3(System::PacketBufferHandle && msg); void OnSuccessStatusReport() override; - CHIP_ERROR OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode) override; + CHIP_ERROR OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode, + Optional protocolData) override; void Finish(); diff --git a/src/protocols/secure_channel/PairingSession.h b/src/protocols/secure_channel/PairingSession.h index 8ed9f269b9a32c..f49dbf7997f4e2 100644 --- a/src/protocols/secure_channel/PairingSession.h +++ b/src/protocols/secure_channel/PairingSession.h @@ -26,6 +26,7 @@ #pragma once #include +#include #include #include #include @@ -129,7 +130,11 @@ class DLL_EXPORT PairingSession : public SessionDelegate void SetPeerSessionId(uint16_t id) { mPeerSessionId.SetValue(id); } virtual void OnSuccessStatusReport() {} - virtual CHIP_ERROR OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode) + + // Handle a failure StatusReport message from the server. protocolData will + // depend on exactly what the generalCode/protocolCode are. + virtual CHIP_ERROR OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode, + Optional protocolData) { return CHIP_ERROR_INTERNAL; } @@ -174,6 +179,7 @@ class DLL_EXPORT PairingSession : public SessionDelegate return CHIP_NO_ERROR; } + Optional protocolData; if (report.GetGeneralCode() == Protocols::SecureChannel::GeneralStatusCode::kBusy && report.GetProtocolCode() == Protocols::SecureChannel::kProtocolCodeBusy) { @@ -189,15 +195,15 @@ class DLL_EXPORT PairingSession : public SessionDelegate } else { - // TODO: CASE: Notify minimum wait time to clients on receiving busy status report #28290 ChipLogProgress(SecureChannel, "Received busy status report with minimum wait time: %u ms", minimumWaitTime); + protocolData.Emplace(minimumWaitTime); } } } // It's very important that we propagate the return value from // OnFailureStatusReport out to the caller. Make sure we return it directly. - return OnFailureStatusReport(report.GetGeneralCode(), report.GetProtocolCode()); + return OnFailureStatusReport(report.GetGeneralCode(), report.GetProtocolCode(), protocolData); } /** diff --git a/src/protocols/secure_channel/SessionEstablishmentDelegate.h b/src/protocols/secure_channel/SessionEstablishmentDelegate.h index a50949e6f6b2e8..c0ba56d9b01e09 100644 --- a/src/protocols/secure_channel/SessionEstablishmentDelegate.h +++ b/src/protocols/secure_channel/SessionEstablishmentDelegate.h @@ -25,6 +25,7 @@ #pragma once +#include #include #include #include @@ -80,6 +81,15 @@ class DLL_EXPORT SessionEstablishmentDelegate */ virtual void OnSessionEstablished(const SessionHandle & session) {} + /** + * Called when the responder has responded with a "busy" status code and + * provided a requested delay. + * + * This call will be followed by an OnSessionEstablishmentError with + * CHIP_ERROR_BUSY as the error. + */ + virtual void OnResponderBusy(System::Clock::Milliseconds16 requestedDelay) {} + virtual ~SessionEstablishmentDelegate() {} }; diff --git a/src/python_testing/TC_EEM_2_1.py b/src/python_testing/TC_EEM_2_1.py index 909380401e49d6..27246b26c272a2 100644 --- a/src/python_testing/TC_EEM_2_1.py +++ b/src/python_testing/TC_EEM_2_1.py @@ -62,24 +62,29 @@ async def test_TC_EEM_2_1(self): "Accuracy measurementType must be ElectricalEnergy") self.step("3") - cumulativeEnergyImported = await self.read_eem_attribute_expect_success("CumulativeEnergyImported") - logger.info(f"Rx'd CumulativeEnergyImported: {cumulativeEnergyImported}") + if self.pics_guard(self.check_pics("EEM.S.A0001")): + cumulativeEnergyImported = await self.read_eem_attribute_expect_success("CumulativeEnergyImported") + logger.info(f"Rx'd CumulativeEnergyImported: {cumulativeEnergyImported}") self.step("4") - cumulativeEnergyExported = await self.read_eem_attribute_expect_success("CumulativeEnergyExported") - logger.info(f"Rx'd CumulativeEnergyExported: {cumulativeEnergyExported}") + if self.pics_guard(self.check_pics("EEM.S.A0002")): + cumulativeEnergyExported = await self.read_eem_attribute_expect_success("CumulativeEnergyExported") + logger.info(f"Rx'd CumulativeEnergyExported: {cumulativeEnergyExported}") self.step("5") - periodicEnergyImported = await self.read_eem_attribute_expect_success("PeriodicEnergyImported") - logger.info(f"Rx'd PeriodicEnergyImported: {periodicEnergyImported}") + if self.pics_guard(self.check_pics("EEM.S.A0003")): + periodicEnergyImported = await self.read_eem_attribute_expect_success("PeriodicEnergyImported") + logger.info(f"Rx'd PeriodicEnergyImported: {periodicEnergyImported}") self.step("6") - periodicEnergyExported = await self.read_eem_attribute_expect_success("PeriodicEnergyExported") - logger.info(f"Rx'd PeriodicEnergyExported: {periodicEnergyExported}") + if self.pics_guard(self.check_pics("EEM.S.A0004")): + periodicEnergyExported = await self.read_eem_attribute_expect_success("PeriodicEnergyExported") + logger.info(f"Rx'd PeriodicEnergyExported: {periodicEnergyExported}") self.step("7") - cumulativeEnergyReset = await self.read_eem_attribute_expect_success("CumulativeEnergyReset") - logger.info(f"Rx'd CumulativeEnergyReset: {cumulativeEnergyReset}") + if self.pics_guard(self.check_pics("EEM.S.A0005")): + cumulativeEnergyReset = await self.read_eem_attribute_expect_success("CumulativeEnergyReset") + logger.info(f"Rx'd CumulativeEnergyReset: {cumulativeEnergyReset}") if __name__ == "__main__": diff --git a/src/python_testing/TC_EEM_2_2.py b/src/python_testing/TC_EEM_2_2.py index 58e651de9425eb..3f3cb5b67cad8b 100644 --- a/src/python_testing/TC_EEM_2_2.py +++ b/src/python_testing/TC_EEM_2_2.py @@ -30,7 +30,7 @@ def desc_TC_EEM_2_2(self) -> str: def pics_TC_EEM_2_2(self): """ This function returns a list of PICS for this test case that must be True for the test to be run""" - return ["EEM.S", "EEM.S.F02(CUME)", "EEM.S.F00(IMPE)"] + return ["EEM.S", "EEM.S.F02", "EEM.S.F00"] def steps_TC_EEM_2_2(self) -> list[TestStep]: steps = [ diff --git a/src/python_testing/TC_EEM_2_3.py b/src/python_testing/TC_EEM_2_3.py index 1183d9591bcd5e..4691043502dfee 100644 --- a/src/python_testing/TC_EEM_2_3.py +++ b/src/python_testing/TC_EEM_2_3.py @@ -30,7 +30,7 @@ def desc_TC_EEM_2_3(self) -> str: def pics_TC_EEM_2_3(self): """ This function returns a list of PICS for this test case that must be True for the test to be run""" - return ["EEM.S", "EEM.S.F02(CUME)", "EEM.S.F01(EXPE)"] + return ["EEM.S", "EEM.S.F02", "EEM.S.F01"] def steps_TC_EEM_2_3(self) -> list[TestStep]: steps = [ diff --git a/src/python_testing/TC_EEM_2_4.py b/src/python_testing/TC_EEM_2_4.py index b219e3c4e770a5..3b8dd346d2a36c 100644 --- a/src/python_testing/TC_EEM_2_4.py +++ b/src/python_testing/TC_EEM_2_4.py @@ -30,7 +30,7 @@ def desc_TC_EEM_2_4(self) -> str: def pics_TC_EEM_2_4(self): """ This function returns a list of PICS for this test case that must be True for the test to be run""" - return ["EEM.S", "EEM.S.F03(PERE)", "EEM.S.F00(IMPE)"] + return ["EEM.S", "EEM.S.F03", "EEM.S.F00"] def steps_TC_EEM_2_4(self) -> list[TestStep]: steps = [ diff --git a/src/python_testing/TC_EEM_2_5.py b/src/python_testing/TC_EEM_2_5.py index 945a97f89da8aa..871fb8e5536743 100644 --- a/src/python_testing/TC_EEM_2_5.py +++ b/src/python_testing/TC_EEM_2_5.py @@ -30,7 +30,7 @@ def desc_TC_EEM_2_5(self) -> str: def pics_TC_EEM_2_5(self): """ This function returns a list of PICS for this test case that must be True for the test to be run""" - return ["EEM.S", "EEM.S.F03(PERE)", "EEM.S.F01(EXPE)"] + return ["EEM.S", "EEM.S.F03", "EEM.S.F01"] def steps_TC_EEM_2_5(self) -> list[TestStep]: steps = [ diff --git a/src/python_testing/TC_EEVSE_2_4.py b/src/python_testing/TC_EEVSE_2_4.py index 9ccad2fdb692db..959932da1fb6cb 100644 --- a/src/python_testing/TC_EEVSE_2_4.py +++ b/src/python_testing/TC_EEVSE_2_4.py @@ -30,7 +30,7 @@ class TC_EEVSE_2_4(MatterBaseTest, EEVSEBaseTestHelper): def desc_TC_EEVSE_2_4(self) -> str: """Returns a description of this test""" - return "5.1.XXX. [TC-EEVSE-2.4] Fault test functionality with DUT as Server" + return "5.1.5. [TC-EEVSE-2.4] Fault test functionality with DUT as Server" def pics_TC_EEVSE_2_4(self): """ This function returns a list of PICS for this test case that must be True for the test to be run""" diff --git a/src/python_testing/TC_EEVSE_2_5.py b/src/python_testing/TC_EEVSE_2_5.py index 00150f263c7576..7ab6efddc40366 100644 --- a/src/python_testing/TC_EEVSE_2_5.py +++ b/src/python_testing/TC_EEVSE_2_5.py @@ -30,12 +30,12 @@ class TC_EEVSE_2_5(MatterBaseTest, EEVSEBaseTestHelper): def desc_TC_EEVSE_2_5(self) -> str: """Returns a description of this test""" - return "5.1.XXX. [TC-EEVSE-2.4] Fault test functionality with DUT as Server" + return "5.1.6. [TC-EEVSE-2.5] Optional diagnostics functionality with DUT as Server" def pics_TC_EEVSE_2_5(self): """ This function returns a list of PICS for this test case that must be True for the test to be run""" - # In this case - there is no feature flags needed to run this test case - return ["EEVSE.S"] + # In this case - we need the EVSE to support the StartDiagnostics command + return ["EEVSE.S", "EEVSE.S.C04.Rsp"] def steps_TC_EEVSE_2_5(self) -> list[TestStep]: steps = [ diff --git a/src/python_testing/TC_EPM_2_2.py b/src/python_testing/TC_EPM_2_2.py index eb6f6081f6d690..756f62f626a0b2 100644 --- a/src/python_testing/TC_EPM_2_2.py +++ b/src/python_testing/TC_EPM_2_2.py @@ -71,31 +71,37 @@ async def test_TC_EPM_2_2(self): time.sleep(3) self.step("4a") + # Active power is Mandatory active_power = await self.check_epm_attribute_in_range("ActivePower", 980000, 1020000) # 1kW +/- 20W self.step("4b") - active_current = await self.check_epm_attribute_in_range("ActiveCurrent", 3848, 4848) # 4.348 A +/- 500mA + if self.pics_guard(self.check_pics("EPM.S.A0005")): + active_current = await self.check_epm_attribute_in_range("ActiveCurrent", 3848, 4848) # 4.348 A +/- 500mA self.step("4c") - voltage = await self.check_epm_attribute_in_range("Voltage", 229000, 231000) # 230V +/- 1V + if self.pics_guard(self.check_pics("EPM.S.A0004")): + voltage = await self.check_epm_attribute_in_range("Voltage", 229000, 231000) # 230V +/- 1V self.step("5") # After 3 seconds... time.sleep(3) self.step("5a") + # Active power is Mandatory active_power2 = await self.check_epm_attribute_in_range("ActivePower", 980000, 1020000) # 1kW +/- 20W asserts.assert_not_equal(active_power, active_power2, f"Expected ActivePower readings to have changed {active_power}, {active_power2}") self.step("5b") - active_current2 = await self.check_epm_attribute_in_range("ActiveCurrent", 3848, 4848) # 4.348 A +/- 500mA - asserts.assert_not_equal(active_current, active_current2, - f"Expected ActiveCurrent readings to have changed {active_current}, {active_current2}") + if self.pics_guard(self.check_pics("EPM.S.A0005")): + active_current2 = await self.check_epm_attribute_in_range("ActiveCurrent", 3848, 4848) # 4.348 A +/- 500mA + asserts.assert_not_equal(active_current, active_current2, + f"Expected ActiveCurrent readings to have changed {active_current}, {active_current2}") self.step("5c") - voltage2 = await self.check_epm_attribute_in_range("Voltage", 229000, 231000) # 230V +/- 1V - asserts.assert_not_equal(voltage, voltage2, f"Expected Voltage readings to have changed {voltage}, {voltage2}") + if self.pics_guard(self.check_pics("EPM.S.A0004")): + voltage2 = await self.check_epm_attribute_in_range("Voltage", 229000, 231000) # 230V +/- 1V + asserts.assert_not_equal(voltage, voltage2, f"Expected Voltage readings to have changed {voltage}, {voltage2}") self.step("6") await self.send_test_event_trigger_stop_fake_readings() diff --git a/src/test_driver/tizen/.gn b/src/test_driver/tizen/.gn index fa6b2fc9621e28..65992f8720b0c5 100644 --- a/src/test_driver/tizen/.gn +++ b/src/test_driver/tizen/.gn @@ -13,6 +13,8 @@ # limitations under the License. import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("//build_overrides/pigweed.gni") # The location of the build configuration file. buildconfig = "${build_root}/config/BUILDCONFIG.gn" @@ -22,4 +24,16 @@ check_system_includes = true default_args = { target_os = "tizen" + + pw_sys_io_BACKEND = "$dir_pw_sys_io_stdio" + pw_assert_BACKEND = "$dir_pw_assert_log" + pw_log_BACKEND = "$dir_pw_log_basic" + + pw_unit_test_BACKEND = "$dir_pw_unit_test:light" + + # TODO: Make sure only unit tests link against this + pw_build_LINK_DEPS = [ + "$dir_pw_assert:impl", + "$dir_pw_log:impl", + ] } diff --git a/src/tracing/tests/BUILD.gn b/src/tracing/tests/BUILD.gn index 6f3ef63df9098d..8f28b56ecb890c 100644 --- a/src/tracing/tests/BUILD.gn +++ b/src/tracing/tests/BUILD.gn @@ -23,13 +23,16 @@ if (matter_enable_tracing_support && matter_trace_config == "multiplexed") { chip_test_suite_using_nltest("tests") { output_name = "libTracingTests" - test_sources = [ "TestTracing.cpp" ] - sources = [] + test_sources = [ + "TestMetricEvents.cpp", + "TestTracing.cpp", + ] public_deps = [ "${chip_root}/src/lib/support:testing_nlunit", "${chip_root}/src/platform", "${chip_root}/src/tracing", + "${chip_root}/src/tracing:macros", "${nlunit_test_root}:nlunit-test", ] } diff --git a/src/tracing/tests/TestMetricEvents.cpp b/src/tracing/tests/TestMetricEvents.cpp new file mode 100644 index 00000000000000..c52a5fc91b9e93 --- /dev/null +++ b/src/tracing/tests/TestMetricEvents.cpp @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include + +#include + +#include +#include +#include + +using namespace chip; +using namespace chip::Tracing; + +namespace chip { +namespace Tracing { + +static bool operator==(const MetricEvent & lhs, const MetricEvent & rhs) +{ + if (&lhs == &rhs) + { + return true; + } + + if (lhs.type() == rhs.type() && std::string(lhs.key()) == std::string(rhs.key()) && lhs.ValueType() == rhs.ValueType()) + { + switch (lhs.ValueType()) + { + case MetricEvent::Value::Type::kInt32: + return lhs.ValueInt32() == rhs.ValueInt32(); + + case MetricEvent::Value::Type::kUInt32: + return lhs.ValueUInt32() == rhs.ValueUInt32(); + + case MetricEvent::Value::Type::kChipErrorCode: + return lhs.ValueErrorCode() == rhs.ValueErrorCode(); + + case MetricEvent::Value::Type::kUndefined: + return true; + } + } + return false; +} +} // namespace Tracing +} // namespace chip + +namespace { + +// This keeps a log of all received trace items +class MetricEventBackend : public Backend +{ +public: + MetricEventBackend() {} + const std::vector & GetMetricEvents() const { return mMetricEvents; } + + // Implementation + virtual void LogMetricEvent(const MetricEvent & event) { mMetricEvents.push_back(event); } + +private: + std::vector mMetricEvents; +}; + +void TestBasicMetricEvent(nlTestSuite * inSuite, void * inContext) +{ + + { + MetricEvent event(MetricEvent::Type::kInstantEvent, "instant_event"); + NL_TEST_ASSERT(inSuite, event.type() == MetricEvent::Type::kInstantEvent); + NL_TEST_ASSERT(inSuite, std::string(event.key()) == std::string("instant_event")); + NL_TEST_ASSERT(inSuite, event.ValueType() == MetricEvent::Value::Type::kUndefined); + } + + { + MetricEvent event(MetricEvent::Type::kBeginEvent, "begin_event"); + NL_TEST_ASSERT(inSuite, event.type() == MetricEvent::Type::kBeginEvent); + NL_TEST_ASSERT(inSuite, std::string(event.key()) == std::string("begin_event")); + NL_TEST_ASSERT(inSuite, event.ValueType() == MetricEvent::Value::Type::kUndefined); + } + + { + MetricEvent event(MetricEvent::Type::kEndEvent, "end_event"); + NL_TEST_ASSERT(inSuite, event.type() == MetricEvent::Type::kEndEvent); + NL_TEST_ASSERT(inSuite, std::string(event.key()) == std::string("end_event")); + NL_TEST_ASSERT(inSuite, event.ValueType() == MetricEvent::Value::Type::kUndefined); + } + + { + MetricEvent event(MetricEvent::Type::kEndEvent, "end_event_with_int32_value", int32_t(42)); + NL_TEST_ASSERT(inSuite, event.type() == MetricEvent::Type::kEndEvent); + NL_TEST_ASSERT(inSuite, std::string(event.key()) == std::string("end_event_with_int32_value")); + NL_TEST_ASSERT(inSuite, event.ValueType() == MetricEvent::Value::Type::kInt32); + NL_TEST_ASSERT(inSuite, event.ValueInt32() == 42); + } + + { + MetricEvent event(MetricEvent::Type::kEndEvent, "end_event_with_uint32_value", uint32_t(42)); + NL_TEST_ASSERT(inSuite, event.type() == MetricEvent::Type::kEndEvent); + NL_TEST_ASSERT(inSuite, std::string(event.key()) == std::string("end_event_with_uint32_value")); + NL_TEST_ASSERT(inSuite, event.ValueType() == MetricEvent::Value::Type::kUInt32); + NL_TEST_ASSERT(inSuite, event.ValueUInt32() == 42u); + } + + { + MetricEvent event(MetricEvent::Type::kEndEvent, "end_event_with_error_value", CHIP_ERROR_BUSY); + NL_TEST_ASSERT(inSuite, event.type() == MetricEvent::Type::kEndEvent); + NL_TEST_ASSERT(inSuite, std::string(event.key()) == std::string("end_event_with_error_value")); + NL_TEST_ASSERT(inSuite, event.ValueType() == MetricEvent::Value::Type::kChipErrorCode); + NL_TEST_ASSERT(inSuite, chip::ChipError(event.ValueErrorCode()) == CHIP_ERROR_BUSY); + } +} + +void TestInstantMetricEvent(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend; + + { + ScopedRegistration scope(backend); + + MATTER_LOG_METRIC("event1"); + MATTER_LOG_METRIC("event2"); + MATTER_LOG_METRIC("event3"); + } + + std::vector expected = { + MetricEvent(MetricEvent::Type::kInstantEvent, "event1"), + MetricEvent(MetricEvent::Type::kInstantEvent, "event2"), + MetricEvent(MetricEvent::Type::kInstantEvent, "event3"), + }; + + NL_TEST_ASSERT(inSuite, backend.GetMetricEvents().size() == expected.size()); + NL_TEST_ASSERT( + inSuite, std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); +} + +void TestBeginEndMetricEvent(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend1; + MetricEventBackend backend2; + + { + ScopedRegistration scope1(backend1); + { + + MATTER_LOG_METRIC_BEGIN("event1"); + MATTER_LOG_METRIC_BEGIN("event2"); + MATTER_LOG_METRIC_END("event2", 53); + MATTER_LOG_METRIC_END("event1"); + } + + std::vector expected1 = { + MetricEvent(MetricEvent::Type::kBeginEvent, "event1"), + MetricEvent(MetricEvent::Type::kBeginEvent, "event2"), + MetricEvent(MetricEvent::Type::kEndEvent, "event2", 53), + MetricEvent(MetricEvent::Type::kEndEvent, "event1"), + }; + + NL_TEST_ASSERT(inSuite, backend1.GetMetricEvents().size() == expected1.size()); + NL_TEST_ASSERT( + inSuite, + std::equal(backend1.GetMetricEvents().begin(), backend1.GetMetricEvents().end(), expected1.begin(), expected1.end())); + + { + ScopedRegistration scope2(backend2); + + MATTER_LOG_METRIC_BEGIN("event1"); + MATTER_LOG_METRIC_BEGIN("event2"); + MATTER_LOG_METRIC_BEGIN("event3"); + MATTER_LOG_METRIC_BEGIN("event4"); + MATTER_LOG_METRIC_END("event3", CHIP_ERROR_UNKNOWN_KEY_TYPE); + MATTER_LOG_METRIC_END("event1", 91u); + MATTER_LOG_METRIC_END("event2", 53); + MATTER_LOG_METRIC_END("event4"); + } + + std::vector expected2 = { + MetricEvent(MetricEvent::Type::kBeginEvent, "event1"), + MetricEvent(MetricEvent::Type::kBeginEvent, "event2"), + MetricEvent(MetricEvent::Type::kBeginEvent, "event3"), + MetricEvent(MetricEvent::Type::kBeginEvent, "event4"), + MetricEvent(MetricEvent::Type::kEndEvent, "event3", CHIP_ERROR_UNKNOWN_KEY_TYPE), + MetricEvent(MetricEvent::Type::kEndEvent, "event1", 91u), + MetricEvent(MetricEvent::Type::kEndEvent, "event2", 53), + MetricEvent(MetricEvent::Type::kEndEvent, "event4"), + }; + + NL_TEST_ASSERT(inSuite, backend2.GetMetricEvents().size() == expected2.size()); + NL_TEST_ASSERT( + inSuite, + std::equal(backend2.GetMetricEvents().begin(), backend2.GetMetricEvents().end(), expected2.begin(), expected2.end())); + } +} + +void TestScopedMetricEvent(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend1; + MetricEventBackend backend2; + MetricEventBackend backend3; + chip::ChipError err1 = CHIP_NO_ERROR; + chip::ChipError err2 = CHIP_NO_ERROR; + chip::ChipError err3 = CHIP_NO_ERROR; + chip::ChipError err4 = CHIP_NO_ERROR; + + { + ScopedRegistration scope1(backend1); + { + MATTER_LOG_METRIC_SCOPE("event1", err1); + err1 = CHIP_ERROR_BUSY; + { + ScopedRegistration scope2(backend2); + MATTER_LOG_METRIC_SCOPE("event2", err2); + err2 = CHIP_ERROR_BAD_REQUEST; + + { + ScopedRegistration scope3(backend3); + MATTER_LOG_METRIC_SCOPE("event3", err3); + err3 = CHIP_ERROR_EVENT_ID_FOUND; + } + { + MATTER_LOG_METRIC_SCOPE("event4", err4); + err4 = CHIP_ERROR_BUFFER_TOO_SMALL; + } + } + } + + std::vector expected1 = { + MetricEvent(MetricEvent::Type::kBeginEvent, "event1"), + MetricEvent(MetricEvent::Type::kBeginEvent, "event2"), + MetricEvent(MetricEvent::Type::kBeginEvent, "event3"), + MetricEvent(MetricEvent::Type::kEndEvent, "event3", CHIP_ERROR_EVENT_ID_FOUND), + MetricEvent(MetricEvent::Type::kBeginEvent, "event4"), + MetricEvent(MetricEvent::Type::kEndEvent, "event4", CHIP_ERROR_BUFFER_TOO_SMALL), + MetricEvent(MetricEvent::Type::kEndEvent, "event2", CHIP_ERROR_BAD_REQUEST), + MetricEvent(MetricEvent::Type::kEndEvent, "event1", CHIP_ERROR_BUSY), + }; + + NL_TEST_ASSERT(inSuite, backend1.GetMetricEvents().size() == expected1.size()); + NL_TEST_ASSERT( + inSuite, + std::equal(backend1.GetMetricEvents().begin(), backend1.GetMetricEvents().end(), expected1.begin(), expected1.end())); + + std::vector expected2 = { + MetricEvent(MetricEvent::Type::kBeginEvent, "event2"), + MetricEvent(MetricEvent::Type::kBeginEvent, "event3"), + MetricEvent(MetricEvent::Type::kEndEvent, "event3", CHIP_ERROR_EVENT_ID_FOUND), + MetricEvent(MetricEvent::Type::kBeginEvent, "event4"), + MetricEvent(MetricEvent::Type::kEndEvent, "event4", CHIP_ERROR_BUFFER_TOO_SMALL), + MetricEvent(MetricEvent::Type::kEndEvent, "event2", CHIP_ERROR_BAD_REQUEST), + }; + + NL_TEST_ASSERT(inSuite, backend2.GetMetricEvents().size() == expected2.size()); + NL_TEST_ASSERT( + inSuite, + std::equal(backend2.GetMetricEvents().begin(), backend2.GetMetricEvents().end(), expected2.begin(), expected2.end())); + + std::vector expected3 = { + MetricEvent(MetricEvent::Type::kBeginEvent, "event3"), + MetricEvent(MetricEvent::Type::kEndEvent, "event3", CHIP_ERROR_EVENT_ID_FOUND), + }; + + NL_TEST_ASSERT(inSuite, backend3.GetMetricEvents().size() == expected3.size()); + NL_TEST_ASSERT( + inSuite, + std::equal(backend3.GetMetricEvents().begin(), backend3.GetMetricEvents().end(), expected3.begin(), expected3.end())); + } +} + +static int DoubleOf(int input) +{ + return input * 2; +} + +void TestVerifyOrExitWithMetric(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend; + ScopedRegistration scope(backend); + chip::ChipError err = CHIP_NO_ERROR; + + VerifyOrExitWithMetric("event0", DoubleOf(2) == 4, err = CHIP_ERROR_BAD_REQUEST); + VerifyOrExitWithMetric("event1", DoubleOf(3) == 9, err = CHIP_ERROR_INCORRECT_STATE); + +exit: + std::vector expected = { + MetricEvent(MetricEvent::Type::kInstantEvent, "event1", CHIP_ERROR_INCORRECT_STATE), + }; + + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INCORRECT_STATE); + NL_TEST_ASSERT(inSuite, backend.GetMetricEvents().size() == expected.size()); + NL_TEST_ASSERT( + inSuite, std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); +} + +void TestSuccessOrExitWithMetric(nlTestSuite * inSuite, void * inContext) +{ + MetricEventBackend backend; + ScopedRegistration scope(backend); + chip::ChipError err = CHIP_NO_ERROR; + + SuccessOrExitWithMetric("event1", err = CHIP_NO_ERROR); + SuccessOrExitWithMetric("event2", err = CHIP_ERROR_BUSY); + SuccessOrExitWithMetric("event3", err = CHIP_NO_ERROR); + +exit: + std::vector expected = { + MetricEvent(MetricEvent::Type::kInstantEvent, "event2", CHIP_ERROR_BUSY), + }; + + NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_BUSY); + NL_TEST_ASSERT(inSuite, backend.GetMetricEvents().size() == expected.size()); + NL_TEST_ASSERT( + inSuite, std::equal(backend.GetMetricEvents().begin(), backend.GetMetricEvents().end(), expected.begin(), expected.end())); +} + +static const nlTest sMetricTests[] = { + NL_TEST_DEF("BasicMetricEvent", TestBasicMetricEvent), // + NL_TEST_DEF("InstantMetricEvent", TestInstantMetricEvent), // + NL_TEST_DEF("BeginEndMetricEvent", TestBeginEndMetricEvent), // + NL_TEST_DEF("ScopedMetricEvent", TestScopedMetricEvent), // + NL_TEST_DEF("VerifyOrExitWithMetric", TestVerifyOrExitWithMetric), // + NL_TEST_DEF("SuccessOrExitWithMetric", TestSuccessOrExitWithMetric), // + NL_TEST_SENTINEL() // +}; + +} // namespace + +int TestMetricEvents() +{ + nlTestSuite theSuite = { "Metric event tests", &sMetricTests[0], nullptr, nullptr }; + + // Run test suite against one context. + nlTestRunner(&theSuite, nullptr); + return nlTestRunnerStats(&theSuite); +} + +CHIP_REGISTER_TEST_SUITE(TestMetricEvents) diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h index be046cb6155993..117f2b78066392 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h @@ -111365,7 +111365,6 @@ class SubscribeAttributeThermostatClusterRevision : public SubscribeAttribute { | Events: | | \*----------------------------------------------------------------------------*/ -#if MTR_ENABLE_PROVISIONAL /* * Command Step */ @@ -111374,15 +111373,9 @@ class FanControlStep : public ClusterCommand { FanControlStep() : ClusterCommand("step") { -#if MTR_ENABLE_PROVISIONAL AddArgument("Direction", 0, UINT8_MAX, &mRequest.direction); -#endif // MTR_ENABLE_PROVISIONAL -#if MTR_ENABLE_PROVISIONAL AddArgument("Wrap", 0, 1, &mRequest.wrap); -#endif // MTR_ENABLE_PROVISIONAL -#if MTR_ENABLE_PROVISIONAL AddArgument("LowestOff", 0, 1, &mRequest.lowestOff); -#endif // MTR_ENABLE_PROVISIONAL ClusterCommand::AddArguments(); } @@ -111397,23 +111390,17 @@ class FanControlStep : public ClusterCommand { __auto_type * cluster = [[MTRBaseClusterFanControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; __auto_type * params = [[MTRFanControlClusterStepParams alloc] init]; params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; -#if MTR_ENABLE_PROVISIONAL params.direction = [NSNumber numberWithUnsignedChar:chip::to_underlying(mRequest.direction)]; -#endif // MTR_ENABLE_PROVISIONAL -#if MTR_ENABLE_PROVISIONAL if (mRequest.wrap.HasValue()) { params.wrap = [NSNumber numberWithBool:mRequest.wrap.Value()]; } else { params.wrap = nil; } -#endif // MTR_ENABLE_PROVISIONAL -#if MTR_ENABLE_PROVISIONAL if (mRequest.lowestOff.HasValue()) { params.lowestOff = [NSNumber numberWithBool:mRequest.lowestOff.Value()]; } else { params.lowestOff = nil; } -#endif // MTR_ENABLE_PROVISIONAL uint16_t repeatCount = mRepeatCount.ValueOr(1); uint16_t __block responsesNeeded = repeatCount; while (repeatCount--) { @@ -111437,8 +111424,6 @@ class FanControlStep : public ClusterCommand { chip::app::Clusters::FanControl::Commands::Step::Type mRequest; }; -#endif // MTR_ENABLE_PROVISIONAL - /* * Attribute FanMode */ @@ -112552,8 +112537,6 @@ class SubscribeAttributeFanControlWindSetting : public SubscribeAttribute { } }; -#if MTR_ENABLE_PROVISIONAL - /* * Attribute AirflowDirection */ @@ -112677,8 +112660,6 @@ class SubscribeAttributeFanControlAirflowDirection : public SubscribeAttribute { } }; -#endif // MTR_ENABLE_PROVISIONAL - /* * Attribute GeneratedCommandList */ @@ -187932,9 +187913,7 @@ void registerClusterFanControl(Commands & commands) commands_list clusterCommands = { make_unique(Id), // -#if MTR_ENABLE_PROVISIONAL make_unique(), // -#endif // MTR_ENABLE_PROVISIONAL make_unique(Id), // make_unique(Id), // make_unique(Id), // @@ -187965,11 +187944,9 @@ void registerClusterFanControl(Commands & commands) make_unique(), // make_unique(), // make_unique(), // -#if MTR_ENABLE_PROVISIONAL make_unique(), // make_unique(), // make_unique(), // -#endif // MTR_ENABLE_PROVISIONAL make_unique(), // make_unique(), // make_unique(), //