diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index f97edf39c9d9db..0c3584f915158f 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -1461,6 +1461,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter index 3b1bd2e565b06d..98c16da49266e7 100644 --- a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter +++ b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter @@ -1090,6 +1090,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/bridge-app/bridge-common/bridge-app.matter b/examples/bridge-app/bridge-common/bridge-app.matter index 64b03dc44a04ff..f4572fce80c57a 100644 --- a/examples/bridge-app/bridge-common/bridge-app.matter +++ b/examples/bridge-app/bridge-common/bridge-app.matter @@ -415,6 +415,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; 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 5b089349467146..055f1a73ff67a2 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 @@ -500,6 +500,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/lighting-app/lighting-common/lighting-app.matter b/examples/lighting-app/lighting-common/lighting-app.matter index 2d2773162d0210..ef2f89ee2ef987 100644 --- a/examples/lighting-app/lighting-common/lighting-app.matter +++ b/examples/lighting-app/lighting-common/lighting-app.matter @@ -513,6 +513,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/lock-app/lock-common/lock-app.matter b/examples/lock-app/lock-common/lock-app.matter index 5cd6c2ca19741e..d5bd0bf37b4c5f 100644 --- a/examples/lock-app/lock-common/lock-app.matter +++ b/examples/lock-app/lock-common/lock-app.matter @@ -822,6 +822,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/log-source-app/log-source-common/log-source-app.matter b/examples/log-source-app/log-source-common/log-source-app.matter index 27160f8d1f08c7..df13f0c7ec186d 100644 --- a/examples/log-source-app/log-source-common/log-source-app.matter +++ b/examples/log-source-app/log-source-common/log-source-app.matter @@ -147,6 +147,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter b/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter index aafc6c5134704b..e8b97b93ae88cf 100644 --- a/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter +++ b/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter @@ -241,6 +241,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter b/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter index 4364dd66e2926a..09184a341332a4 100644 --- a/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter +++ b/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter @@ -175,6 +175,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/placeholder/linux/apps/app1/config.matter b/examples/placeholder/linux/apps/app1/config.matter index 37bb895aca9159..a43b8cc48939bd 100644 --- a/examples/placeholder/linux/apps/app1/config.matter +++ b/examples/placeholder/linux/apps/app1/config.matter @@ -608,6 +608,7 @@ client cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; @@ -654,6 +655,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/placeholder/linux/apps/app2/config.matter b/examples/placeholder/linux/apps/app2/config.matter index 37bb895aca9159..a43b8cc48939bd 100644 --- a/examples/placeholder/linux/apps/app2/config.matter +++ b/examples/placeholder/linux/apps/app2/config.matter @@ -608,6 +608,7 @@ client cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; @@ -654,6 +655,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/pump-app/pump-common/pump-app.matter b/examples/pump-app/pump-common/pump-app.matter index f9f71aafd60633..4e1febd4c9a69f 100644 --- a/examples/pump-app/pump-common/pump-app.matter +++ b/examples/pump-app/pump-common/pump-app.matter @@ -215,6 +215,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter b/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter index bd4f0b6618d76a..5c9fd57944fd1b 100644 --- a/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter +++ b/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter @@ -238,6 +238,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/temperature-measurement-app/esp32/main/temperature-measurement.matter b/examples/temperature-measurement-app/esp32/main/temperature-measurement.matter index 5a5c5da7c76e32..335c0909c0729b 100644 --- a/examples/temperature-measurement-app/esp32/main/temperature-measurement.matter +++ b/examples/temperature-measurement-app/esp32/main/temperature-measurement.matter @@ -250,6 +250,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/thermostat/thermostat-common/thermostat.matter b/examples/thermostat/thermostat-common/thermostat.matter index 6dcea48abc753b..a86aad69a981d9 100644 --- a/examples/thermostat/thermostat-common/thermostat.matter +++ b/examples/thermostat/thermostat-common/thermostat.matter @@ -262,6 +262,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/tv-app/tv-common/tv-app.matter b/examples/tv-app/tv-common/tv-app.matter index 4759b9fbe1cfd9..7654b8170e0789 100644 --- a/examples/tv-app/tv-common/tv-app.matter +++ b/examples/tv-app/tv-common/tv-app.matter @@ -575,6 +575,7 @@ client cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; @@ -633,6 +634,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter b/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter index f3dd20e6668137..f2af646689e52e 100644 --- a/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter +++ b/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter @@ -555,6 +555,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/examples/window-app/common/window-app.matter b/examples/window-app/common/window-app.matter index 37ec6085a3d5a1..20c5a7e539dc90 100644 --- a/examples/window-app/common/window-app.matter +++ b/examples/window-app/common/window-app.matter @@ -227,6 +227,7 @@ server cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp b/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp index 64aa0c9520954b..f86eecf51eea6e 100644 --- a/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp +++ b/src/app/clusters/general-commissioning-server/general-commissioning-server.cpp @@ -129,7 +129,10 @@ CHIP_ERROR GeneralCommissioningAttrAccess::ReadBasicCommissioningInfo(AttributeV // TODO: The commissioner might use the critical parameters in BasicCommissioningInfo to initialize // the CommissioningParameters at the beginning of commissioning flow. - basicCommissioningInfo.failSafeExpiryLengthSeconds = CHIP_DEVICE_CONFIG_FAILSAFE_EXPIRY_LENGTH_SEC; + basicCommissioningInfo.failSafeExpiryLengthSeconds = CHIP_DEVICE_CONFIG_FAILSAFE_EXPIRY_LENGTH_SEC; + basicCommissioningInfo.maxCumulativeFailsafeSeconds = CHIP_DEVICE_CONFIG_MAX_CUMULATIVE_FAILSAFE_SEC; + static_assert(CHIP_DEVICE_CONFIG_MAX_CUMULATIVE_FAILSAFE_SEC >= CHIP_DEVICE_CONFIG_FAILSAFE_EXPIRY_LENGTH_SEC, + "Max cumulative failsafe seconds must be larger than failsafe expiry length seconds"); return aEncoder.Encode(basicCommissioningInfo); } @@ -140,7 +143,7 @@ CHIP_ERROR GeneralCommissioningAttrAccess::ReadSupportsConcurrentConnection(Attr // TODO: The commissioner might use the critical parameters in BasicCommissioningInfo to initialize // the CommissioningParameters at the beginning of commissioning flow. - supportsConcurrentConnection = (CHIP_DEVICE_CONFIG_FAILSAFE_EXPIRY_LENGTH_SEC) != 0; + supportsConcurrentConnection = (CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION) != 0; return aEncoder.Encode(supportsConcurrentConnection); } diff --git a/src/app/tests/suites/certification/Test_TC_CGEN_2_1.yaml b/src/app/tests/suites/certification/Test_TC_CGEN_2_1.yaml index 97ce7e6e23a017..22ad7b6b227053 100644 --- a/src/app/tests/suites/certification/Test_TC_CGEN_2_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_CGEN_2_1.yaml @@ -71,4 +71,8 @@ tests: command: "readAttribute" attribute: "BasicCommissioningInfo" response: - value: { FailSafeExpiryLengthSeconds: 60 } + value: + { + FailSafeExpiryLengthSeconds: 60, + MaxCumulativeFailsafeSeconds: 900, + } diff --git a/src/app/zap-templates/zcl/data-model/chip/general-commissioning-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/general-commissioning-cluster.xml index eb1006294b7db2..0d913e68dc9653 100644 --- a/src/app/zap-templates/zcl/data-model/chip/general-commissioning-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/general-commissioning-cluster.xml @@ -32,7 +32,8 @@ limitations under the License. - + + General diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 8693e3cca8e109..921f17b4d3cfcc 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -1811,6 +1811,7 @@ client cluster GeneralCommissioning = 48 { struct BasicCommissioningInfo { int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; } attribute access(write: administer) int64u breadcrumb = 0; diff --git a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp index eb6a3def6b8626..346b0f80aac941 100644 --- a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp @@ -6508,6 +6508,12 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR chip::JniReferences::GetInstance().CreateBoxedObject( value_failSafeExpiryLengthSecondsClassName.c_str(), value_failSafeExpiryLengthSecondsCtorSignature.c_str(), cppValue.failSafeExpiryLengthSeconds, value_failSafeExpiryLengthSeconds); + jobject value_maxCumulativeFailsafeSeconds; + std::string value_maxCumulativeFailsafeSecondsClassName = "java/lang/Integer"; + std::string value_maxCumulativeFailsafeSecondsCtorSignature = "(I)V"; + chip::JniReferences::GetInstance().CreateBoxedObject( + value_maxCumulativeFailsafeSecondsClassName.c_str(), value_maxCumulativeFailsafeSecondsCtorSignature.c_str(), + cppValue.maxCumulativeFailsafeSeconds, value_maxCumulativeFailsafeSeconds); jclass basicCommissioningInfoStructClass; err = chip::JniReferences::GetInstance().GetClassRef( @@ -6519,7 +6525,7 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR return nullptr; } jmethodID basicCommissioningInfoStructCtor = - env->GetMethodID(basicCommissioningInfoStructClass, "", "(Ljava/lang/Integer;)V"); + env->GetMethodID(basicCommissioningInfoStructClass, "", "(Ljava/lang/Integer;Ljava/lang/Integer;)V"); if (basicCommissioningInfoStructCtor == nullptr) { ChipLogError(Zcl, "Could not find ChipStructs$GeneralCommissioningClusterBasicCommissioningInfo constructor"); @@ -6527,7 +6533,7 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR } value = env->NewObject(basicCommissioningInfoStructClass, basicCommissioningInfoStructCtor, - value_failSafeExpiryLengthSeconds); + value_failSafeExpiryLengthSeconds, value_maxCumulativeFailsafeSeconds); return value; } case Attributes::RegulatoryConfig::Id: { diff --git a/src/controller/java/zap-generated/chip/devicecontroller/ChipStructs.java b/src/controller/java/zap-generated/chip/devicecontroller/ChipStructs.java index 4affe8b8bd6946..9d8a6817b40d2e 100644 --- a/src/controller/java/zap-generated/chip/devicecontroller/ChipStructs.java +++ b/src/controller/java/zap-generated/chip/devicecontroller/ChipStructs.java @@ -722,9 +722,12 @@ public String toString() { public static class GeneralCommissioningClusterBasicCommissioningInfo { public Integer failSafeExpiryLengthSeconds; + public Integer maxCumulativeFailsafeSeconds; - public GeneralCommissioningClusterBasicCommissioningInfo(Integer failSafeExpiryLengthSeconds) { + public GeneralCommissioningClusterBasicCommissioningInfo( + Integer failSafeExpiryLengthSeconds, Integer maxCumulativeFailsafeSeconds) { this.failSafeExpiryLengthSeconds = failSafeExpiryLengthSeconds; + this.maxCumulativeFailsafeSeconds = maxCumulativeFailsafeSeconds; } @Override @@ -734,6 +737,9 @@ public String toString() { output.append("\tfailSafeExpiryLengthSeconds: "); output.append(failSafeExpiryLengthSeconds); output.append("\n"); + output.append("\tmaxCumulativeFailsafeSeconds: "); + output.append(maxCumulativeFailsafeSeconds); + output.append("\n"); output.append("}\n"); return output.toString(); } diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index 47d298a82c9e62..1015d9e6a8c4f8 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -9306,9 +9306,11 @@ def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields = [ ClusterObjectFieldDescriptor(Label="failSafeExpiryLengthSeconds", Tag=0, Type=uint), + ClusterObjectFieldDescriptor(Label="maxCumulativeFailsafeSeconds", Tag=1, Type=uint), ]) failSafeExpiryLengthSeconds: 'uint' = 0 + maxCumulativeFailsafeSeconds: 'uint' = 0 diff --git a/src/darwin/Framework/CHIP/zap-generated/CHIPAttributeTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/CHIPAttributeTLVValueDecoder.mm index ab760ef91f6bc8..874fa3b86175ad 100644 --- a/src/darwin/Framework/CHIP/zap-generated/CHIPAttributeTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/CHIPAttributeTLVValueDecoder.mm @@ -6815,6 +6815,7 @@ id CHIPDecodeAttributeValue(const ConcreteAttributePath & aPath, TLV::TLVReader CHIPGeneralCommissioningClusterBasicCommissioningInfo * _Nonnull value; value = [CHIPGeneralCommissioningClusterBasicCommissioningInfo new]; value.failSafeExpiryLengthSeconds = [NSNumber numberWithUnsignedShort:cppValue.failSafeExpiryLengthSeconds]; + value.maxCumulativeFailsafeSeconds = [NSNumber numberWithUnsignedShort:cppValue.maxCumulativeFailsafeSeconds]; return value; } case Attributes::RegulatoryConfig::Id: { diff --git a/src/darwin/Framework/CHIP/zap-generated/CHIPCallbackBridge.mm b/src/darwin/Framework/CHIP/zap-generated/CHIPCallbackBridge.mm index 7cc6117360727e..a37a04bc9a29bf 100644 --- a/src/darwin/Framework/CHIP/zap-generated/CHIPCallbackBridge.mm +++ b/src/darwin/Framework/CHIP/zap-generated/CHIPCallbackBridge.mm @@ -4569,6 +4569,7 @@ CHIPGeneralCommissioningClusterBasicCommissioningInfo * _Nonnull objCValue; objCValue = [CHIPGeneralCommissioningClusterBasicCommissioningInfo new]; objCValue.failSafeExpiryLengthSeconds = [NSNumber numberWithUnsignedShort:value.failSafeExpiryLengthSeconds]; + objCValue.maxCumulativeFailsafeSeconds = [NSNumber numberWithUnsignedShort:value.maxCumulativeFailsafeSeconds]; DispatchSuccess(context, objCValue); }; diff --git a/src/darwin/Framework/CHIP/zap-generated/CHIPStructsObjc.h b/src/darwin/Framework/CHIP/zap-generated/CHIPStructsObjc.h index a1f9e206f889d0..4af265ab387183 100644 --- a/src/darwin/Framework/CHIP/zap-generated/CHIPStructsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/CHIPStructsObjc.h @@ -210,6 +210,7 @@ NS_ASSUME_NONNULL_BEGIN @interface CHIPGeneralCommissioningClusterBasicCommissioningInfo : NSObject @property (strong, nonatomic) NSNumber * _Nonnull failSafeExpiryLengthSeconds; +@property (strong, nonatomic) NSNumber * _Nonnull maxCumulativeFailsafeSeconds; - (instancetype)init; @end diff --git a/src/darwin/Framework/CHIP/zap-generated/CHIPStructsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/CHIPStructsObjc.mm index 9d9a5958fdfab2..1e8fcd3cc81245 100644 --- a/src/darwin/Framework/CHIP/zap-generated/CHIPStructsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/CHIPStructsObjc.mm @@ -677,14 +677,17 @@ - (instancetype)init if (self = [super init]) { _failSafeExpiryLengthSeconds = @(0); + + _maxCumulativeFailsafeSeconds = @(0); } return self; } - (NSString *)description { - NSString * descriptionString = [NSString - stringWithFormat:@"<%@: failSafeExpiryLengthSeconds:%@; >", NSStringFromClass([self class]), _failSafeExpiryLengthSeconds]; + NSString * descriptionString = + [NSString stringWithFormat:@"<%@: failSafeExpiryLengthSeconds:%@; maxCumulativeFailsafeSeconds:%@; >", + NSStringFromClass([self class]), _failSafeExpiryLengthSeconds, _maxCumulativeFailsafeSeconds]; return descriptionString; } diff --git a/src/include/platform/CHIPDeviceConfig.h b/src/include/platform/CHIPDeviceConfig.h index 286efee3a7c1a2..1ec81fdc5e5bfd 100644 --- a/src/include/platform/CHIPDeviceConfig.h +++ b/src/include/platform/CHIPDeviceConfig.h @@ -257,6 +257,16 @@ #define CHIP_DEVICE_CONFIG_FAILSAFE_EXPIRY_LENGTH_SEC 60 #endif // CHIP_DEVICE_CONFIG_FAILSAFE_EXPIRY_LENGTH_SEC +/** + * CHIP_DEVICE_CONFIG_MAX_CUMULATIVE_FAILSAFE_SEC + * + * The default conservative value in seconds denoting the maximum total duration for which a fail safe + * timer can be re-armed. + */ +#ifndef CHIP_DEVICE_CONFIG_MAX_CUMULATIVE_FAILSAFE_SEC +#define CHIP_DEVICE_CONFIG_MAX_CUMULATIVE_FAILSAFE_SEC 900 +#endif // CHIP_DEVICE_CONFIG_MAX_CUMULATIVE_FAILSAFE_SEC + /** * CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION * diff --git a/src/include/platform/FailSafeContext.h b/src/include/platform/FailSafeContext.h index ce7a3300efd97e..1af60d71a21a37 100644 --- a/src/include/platform/FailSafeContext.h +++ b/src/include/platform/FailSafeContext.h @@ -116,6 +116,12 @@ class FailSafeContext */ static void HandleArmFailSafeTimer(System::Layer * layer, void * aAppState); + /** + * @brief + * The callback function to be called when max cumulative time expires. + */ + static void HandleMaxCumulativeFailSafeTimer(System::Layer * layer, void * aAppState); + /** * @brief * The callback function to be called asynchronously after various cleanup work has completed diff --git a/src/platform/FailSafeContext.cpp b/src/platform/FailSafeContext.cpp index 6bb4a0c3d19b9f..376881b05fab51 100644 --- a/src/platform/FailSafeContext.cpp +++ b/src/platform/FailSafeContext.cpp @@ -41,6 +41,12 @@ void FailSafeContext::HandleArmFailSafeTimer(System::Layer * layer, void * aAppS failSafeContext->FailSafeTimerExpired(); } +void FailSafeContext::HandleMaxCumulativeFailSafeTimer(System::Layer * layer, void * aAppState) +{ + FailSafeContext * failSafeContext = reinterpret_cast(aAppState); + failSafeContext->FailSafeTimerExpired(); +} + void FailSafeContext::HandleDisarmFailSafe(intptr_t arg) { FailSafeContext * failSafeContext = reinterpret_cast(arg); @@ -85,19 +91,36 @@ void FailSafeContext::ScheduleFailSafeCleanup(FabricIndex fabricIndex, bool addN CHIP_ERROR FailSafeContext::ArmFailSafe(FabricIndex accessingFabricIndex, System::Clock::Timeout expiryLength) { + CHIP_ERROR err = CHIP_NO_ERROR; + bool cancelTimersIfError = false; + if (!mFailSafeArmed) + { + System::Clock::Timeout maxCumulativeTimeout = System::Clock::Seconds32(CHIP_DEVICE_CONFIG_MAX_CUMULATIVE_FAILSAFE_SEC); + SuccessOrExit(err = DeviceLayer::SystemLayer().StartTimer(maxCumulativeTimeout, HandleMaxCumulativeFailSafeTimer, this)); + cancelTimersIfError = true; + } + + SuccessOrExit(err = DeviceLayer::SystemLayer().StartTimer(expiryLength, HandleArmFailSafeTimer, this)); + SuccessOrExit(err = CommitToStorage()); + SuccessOrExit(err = ConfigurationMgr().SetFailSafeArmed(true)); + mFailSafeArmed = true; mFabricIndex = accessingFabricIndex; - ReturnErrorOnFailure(DeviceLayer::SystemLayer().StartTimer(expiryLength, HandleArmFailSafeTimer, this)); - ReturnErrorOnFailure(CommitToStorage()); - ReturnErrorOnFailure(ConfigurationMgr().SetFailSafeArmed(true)); +exit: - return CHIP_NO_ERROR; + if (err != CHIP_NO_ERROR && cancelTimersIfError) + { + DeviceLayer::SystemLayer().CancelTimer(HandleArmFailSafeTimer, this); + DeviceLayer::SystemLayer().CancelTimer(HandleMaxCumulativeFailSafeTimer, this); + } + return err; } void FailSafeContext::DisarmFailSafe() { DeviceLayer::SystemLayer().CancelTimer(HandleArmFailSafeTimer, this); + DeviceLayer::SystemLayer().CancelTimer(HandleMaxCumulativeFailSafeTimer, this); ResetState(); @@ -200,6 +223,7 @@ void FailSafeContext::ForceFailSafeTimerExpiry() // Cancel the timer since we force its action DeviceLayer::SystemLayer().CancelTimer(HandleArmFailSafeTimer, this); + DeviceLayer::SystemLayer().CancelTimer(HandleMaxCumulativeFailSafeTimer, this); FailSafeTimerExpired(); } diff --git a/zzz_generated/app-common/app-common/zap-generated/af-structs.h b/zzz_generated/app-common/app-common/zap-generated/af-structs.h index 8aeb3f7108f1c4..6f607f51bc2008 100644 --- a/zzz_generated/app-common/app-common/zap-generated/af-structs.h +++ b/zzz_generated/app-common/app-common/zap-generated/af-structs.h @@ -230,6 +230,7 @@ typedef struct _ApplicationBasicApplication typedef struct _BasicCommissioningInfo { uint16_t FailSafeExpiryLengthSeconds; + uint16_t MaxCumulativeFailsafeSeconds; } BasicCommissioningInfo; // Struct for BatChargeFaultChangeType diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp index 4efa5aa127e4a3..ee9f8f54f28bfc 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp @@ -7536,6 +7536,8 @@ CHIP_ERROR Type::Encode(TLV::TLVWriter & writer, TLV::Tag tag) const ReturnErrorOnFailure(writer.StartContainer(tag, TLV::kTLVType_Structure, outer)); ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kFailSafeExpiryLengthSeconds)), failSafeExpiryLengthSeconds)); + ReturnErrorOnFailure(DataModel::Encode(writer, TLV::ContextTag(to_underlying(Fields::kMaxCumulativeFailsafeSeconds)), + maxCumulativeFailsafeSeconds)); ReturnErrorOnFailure(writer.EndContainer(outer)); return CHIP_NO_ERROR; } @@ -7558,6 +7560,9 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) case to_underlying(Fields::kFailSafeExpiryLengthSeconds): ReturnErrorOnFailure(DataModel::Decode(reader, failSafeExpiryLengthSeconds)); break; + case to_underlying(Fields::kMaxCumulativeFailsafeSeconds): + ReturnErrorOnFailure(DataModel::Decode(reader, maxCumulativeFailsafeSeconds)); + break; default: break; } diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h index 02ae1fee8cf8ef..4d7591ab81cae6 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h @@ -9596,13 +9596,15 @@ namespace Structs { namespace BasicCommissioningInfo { enum class Fields { - kFailSafeExpiryLengthSeconds = 0, + kFailSafeExpiryLengthSeconds = 0, + kMaxCumulativeFailsafeSeconds = 1, }; struct Type { public: - uint16_t failSafeExpiryLengthSeconds = static_cast(0); + uint16_t failSafeExpiryLengthSeconds = static_cast(0); + uint16_t maxCumulativeFailsafeSeconds = static_cast(0); CHIP_ERROR Decode(TLV::TLVReader & reader); diff --git a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp index 7a45aad94a559e..1e8d2717d7e2d2 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp @@ -249,18 +249,26 @@ CHIP_ERROR ComplexArgumentParser::Setup(const char * label, ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("BasicCommissioningInfo.failSafeExpiryLengthSeconds", "failSafeExpiryLengthSeconds", value.isMember("failSafeExpiryLengthSeconds"))); + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("BasicCommissioningInfo.maxCumulativeFailsafeSeconds", + "maxCumulativeFailsafeSeconds", + value.isMember("maxCumulativeFailsafeSeconds"))); char labelWithMember[kMaxLabelLength]; snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "failSafeExpiryLengthSeconds"); ReturnErrorOnFailure( ComplexArgumentParser::Setup(labelWithMember, request.failSafeExpiryLengthSeconds, value["failSafeExpiryLengthSeconds"])); + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "maxCumulativeFailsafeSeconds"); + ReturnErrorOnFailure( + ComplexArgumentParser::Setup(labelWithMember, request.maxCumulativeFailsafeSeconds, value["maxCumulativeFailsafeSeconds"])); + return CHIP_NO_ERROR; } void ComplexArgumentParser::Finalize(chip::app::Clusters::GeneralCommissioning::Structs::BasicCommissioningInfo::Type & request) { ComplexArgumentParser::Finalize(request.failSafeExpiryLengthSeconds); + ComplexArgumentParser::Finalize(request.maxCumulativeFailsafeSeconds); } CHIP_ERROR ComplexArgumentParser::Setup(const char * label, chip::app::Clusters::PowerSource::Structs::BatChargeFaultChangeType::Type & request, diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp index ff098c4947446a..0a3f17efc7450d 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp @@ -259,6 +259,14 @@ DataModelLogger::LogValue(const char * label, size_t indent, return err; } } + { + CHIP_ERROR err = LogValue("MaxCumulativeFailsafeSeconds", indent + 1, value.maxCumulativeFailsafeSeconds); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'MaxCumulativeFailsafeSeconds'"); + return err; + } + } DataModelLogger::LogString(indent, "}"); return CHIP_NO_ERROR; diff --git a/zzz_generated/chip-tool/zap-generated/test/Commands.h b/zzz_generated/chip-tool/zap-generated/test/Commands.h index 289cdf531bca03..5594731c164d58 100644 --- a/zzz_generated/chip-tool/zap-generated/test/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/test/Commands.h @@ -13401,6 +13401,8 @@ class Test_TC_CGEN_2_1Suite : public TestCommand VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value))); VerifyOrReturn( CheckValue("basicCommissioningInfo.failSafeExpiryLengthSeconds", value.failSafeExpiryLengthSeconds, 60U)); + VerifyOrReturn( + CheckValue("basicCommissioningInfo.maxCumulativeFailsafeSeconds", value.maxCumulativeFailsafeSeconds, 900U)); } break; default: diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/CHIPTestClustersObjc.mm b/zzz_generated/darwin-framework-tool/zap-generated/cluster/CHIPTestClustersObjc.mm index 84f6f74656e8b0..0ad47c8b713e04 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/CHIPTestClustersObjc.mm +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/CHIPTestClustersObjc.mm @@ -9257,6 +9257,7 @@ new CHIPDefaultSuccessCallbackBridge( using TypeInfo = GeneralCommissioning::Attributes::BasicCommissioningInfo::TypeInfo; TypeInfo::Type cppValue; cppValue.failSafeExpiryLengthSeconds = value.failSafeExpiryLengthSeconds.unsignedShortValue; + cppValue.maxCumulativeFailsafeSeconds = value.maxCumulativeFailsafeSeconds.unsignedShortValue; auto successFn = Callback::FromCancelable(success); auto failureFn = Callback::FromCancelable(failure); return self.cppCluster.WriteAttribute(cppValue, successFn->mContext, successFn->mCall, failureFn->mCall); diff --git a/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h index 6dcad1e170e5db..6aaab0eb855f61 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h @@ -22678,6 +22678,8 @@ class Test_TC_CGEN_2_1 : public TestCommandBridge { id actualValue = value; VerifyOrReturn(CheckValue("FailSafeExpiryLengthSeconds", ((CHIPGeneralCommissioningClusterBasicCommissioningInfo *) actualValue).failSafeExpiryLengthSeconds, 60U)); + VerifyOrReturn(CheckValue("MaxCumulativeFailsafeSeconds", + ((CHIPGeneralCommissioningClusterBasicCommissioningInfo *) actualValue).maxCumulativeFailsafeSeconds, 900U)); } NextTest();