From e782f539cb74348977036d8a20e03b5d6c52d4a6 Mon Sep 17 00:00:00 2001 From: Martin Girardot <165289184+Martin-NXP@users.noreply.github.com> Date: Tue, 26 Nov 2024 17:51:13 +0100 Subject: [PATCH 01/26] [NXP] Add EL2GO factory data impl, change default rw61x factory data impl (#36615) * [NXP][platform] Add EL2GO factory data implementation, update default factory data implmentation to use secure element Signed-off-by: Martin Girardot * [NXP][exmples] Add EL2GO factory data implementation, update default factory data implmentation to use secure element Signed-off-by: Martin Girardot * [NXP][script] Add EL2GO factory data implementation Signed-off-by: Martin Girardot * [NXP][doc] Add EL2GO factory data implementation, update default factory data implmentation to use secure element Signed-off-by: Martin Girardot * Restyled by whitespace * Restyled by clang-format * Restyled by gn * Restyled by prettier-markdown * Restyled by autopep8 * Restyled by isort * [NXP] fix spelling Signed-off-by: Martin Girardot * [NXP][submodule] Update NXP matter support submodule Signed-off-by: Martin Girardot * [NXP] Add factory data secure key storage compatiblity with actual factory data Signed-off-by: Martin Girardot --------- Signed-off-by: Martin Girardot Co-authored-by: Restyled.io --- docs/platforms/nxp/nxp_manufacturing_flow.md | 115 +++---- .../all-clusters-app/nxp/rt/rw61x/BUILD.gn | 15 +- .../laundry-washer-app/nxp/rt/rw61x/BUILD.gn | 13 +- examples/thermostat/nxp/rt/rw61x/BUILD.gn | 15 +- .../nxp/factory_data_generator/custom.py | 27 ++ .../nxp/factory_data_generator/generate.py | 37 ++- .../common/factory_data/FactoryDataProvider.h | 21 +- src/platform/nxp/rt/rw61x/BUILD.gn | 34 +-- .../rt/rw61x/FactoryDataProviderEl2GoImpl.cpp | 283 ++++++++++++++++++ .../rt/rw61x/FactoryDataProviderEl2GoImpl.h | 77 +++++ .../nxp/rt/rw61x/FactoryDataProviderImpl.cpp | 119 +++++++- .../nxp/rt/rw61x/FactoryDataProviderImpl.h | 9 +- third_party/nxp/nxp_matter_support | 2 +- 13 files changed, 621 insertions(+), 146 deletions(-) create mode 100644 src/platform/nxp/rt/rw61x/FactoryDataProviderEl2GoImpl.cpp create mode 100644 src/platform/nxp/rt/rw61x/FactoryDataProviderEl2GoImpl.h diff --git a/docs/platforms/nxp/nxp_manufacturing_flow.md b/docs/platforms/nxp/nxp_manufacturing_flow.md index 28618b276a5e01..0f30d0612b1f81 100644 --- a/docs/platforms/nxp/nxp_manufacturing_flow.md +++ b/docs/platforms/nxp/nxp_manufacturing_flow.md @@ -103,8 +103,6 @@ Here is the interpretation of the **required** parameters: --hw_version -> Hardware Version as number --hw_version_str -> Hardware Version as string --cert_declaration -> path to the Certification Declaration (der format) location ---dac_cert -> path to the DAC (der format) location ---dac_key -> path to the DAC key (der format) location --pai_cert -> path to the PAI (der format) location --spake2p_path -> path to the spake2p tool --out -> name of the binary that will be used for storing all the generated data @@ -113,6 +111,11 @@ Here is the interpretation of the **required** parameters: Here is the interpretation of the **optional** parameters: ```shell +--dac_cert -> path to the DAC certificate (der format) location +--dac_key -> path to the DAC key (der format) location +--EL2GO_bin -> path to the EdgeLock 2Go binary (bin format) location +--EL2GO_DAC_KEY_ID -> DAC key ID configured into EdgeLock 2Go as hex value +--EL2GO_DAC_CERT_ID -> DAC certificate ID configured into EdgeLock 2Go as hex value --dac_key_password -> Password to decode DAC key --dac_key_use_sss_blob -> Used when --dac_key contains a path to an encrypted blob, instead of the actual DAC private key. The blob metadata size is 24, so the total length @@ -182,17 +185,56 @@ Also, demo **DAC**, **PAI** and **PAA** certificates needed in case ## 6. Increased security for DAC private key -### 6.1 SSS-based platforms +### 6.1 SSS-based with EdgeLock2go support + +EdgeLock2go services could be used to securely provisioned DAC key/cert during +manufacturing. + +Prior to the generation of the factory data binary. `EL2GO` data needs to be +generated following `EL2GO` process. + +For the factory data generation following option need to be added: + +`--EL2GO_bin ~/secure_objects.bin` containing `EL2GO` information including +encrypted DAC private key and certificate. `--EL2GO_DAC_KEY_ID 1234` containing +corresponding to the ID of the DAC key chosen during `EL2GO` key generation. +`--EL2GO_DAC_CERT_ID 4321` containing corresponding to the ID of the DAC +certification chosen during `EL2GO` key generation. + +Reference factory data generation command: + +```shell +python3 ./scripts/tools/nxp/factory_data_generator/generate.py -i 10000 -s UXKLzwHdN3DZZLBaL2iVGhQi/OoQwIwJRQV4rpEalbA= -p ${passcode} -d ${discriminator} --vid "0x$VID" --pid "0x$PID" --vendor_name "NXP Semiconductors" --product_name "Thermostat" --serial_num "12345678" --date "$DATE" --hw_version 1 --hw_version_str "1.0" --cert_declaration $FACTORY_DATA_DEST/Chip-Test-CD-$VID-$PID.der --EL2GO_bin ~/secure_objects.bin --EL2GO_DAC_KEY_ID 1234 --EL2GO_DAC_CERT_ID 4321 --pai_cert $FACTORY_DATA_DEST/Chip-PAI-NXP-$VID-$PID-Cert.der --spake2p_path ./out/spake2p --unique_id "00112233445566778899aabbccddeeff" --out $FACTORY_DATA_DEST/factory_data.bin +``` + +Supported platforms: + +- `rw61x` + +In addition to the GN flag `nxp_use_factory_data=true`, a Matter application +needs to be built with `nxp_enable_secure_EL2GO_factory_data=true` to allow +loading of EdgeLock2go data to the secure element. + +In this mode EdgeLock2go keys will always remain encrypted and only usable by +the `SSS`. In this case, all operations that requires DAC private access will be +transferred to the `SSS`. + +### 6.2 SSS-based without EdgeLock2go support for DAC private key secure storage Supported platforms: - `k32w1` - `mcxw71` +- `rw61x` For platforms that have a secure subsystem (`SSS`), the DAC private key can be converted to an encrypted blob. This blob will overwrite the DAC private key in -factory data and will be imported in the `SSS` at initialization, by the factory -data provider instance. +factory data and will be imported in the `SSS` by the factory data provider +instance. + +In this architecture, outside of the manufacturing flow, the DAC private will +always remain usable only by the `SSS`. In this case, all operations that +requires DAC private access will be transferred to the `SSS`. The application will check at initialization whether the DAC private key has been converted or not and convert it if needed. However, the conversion process @@ -226,64 +268,5 @@ Please note that `--dac_key` now points to a binary file that contains the encrypted blob. The user can use the DAC private in plain text instead of using the `SSS` by -adding the following gn argument `chip_use_plain_dac_key=true`. - -### 6.2 RW61X - -Supported platforms: - -- RW61X - -there are three implementations for factory data protection - -- whole factory data protection with AES encryption ( - nxp_use_factory_data=true nxp_enable_secure_whole_factory_data=true ) - `examples/platform/nxp/rt/rw61x/factory_data/source/AppFactoryDataExample.cpp`\ - `src/platform/nxp/rt/rw61x/FactoryDataProviderEncImpl.cpp` - -- only dac private key protection ( nxp_use_factory_data=true - nxp_enable_secure_dac_private_key_storage=true ) - `examples/platform/nxp/rt/rw61x/factory_data/source/AppFactoryDataExample.cpp` - \ - `src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.cpp` - -- whole factory data protection with hard-coded AES key ( - nxp_use_factory_data=true ) - `examples/platform/nxp/common/factory_data/source/AppFactoryDataDefaultImpl.cpp` - \ - `src/platform/nxp/common/factory_data/FactoryDataProviderFwkImpl.cpp` - -for the first one, the whole factory data is encrypted by an AES-256 key, the -AES key can be passed through serial link when in factory production mode, and -will be provisioned into Edge Lock, and the returned AES Key blob (wrapped key) -can be stored in the end of factory data region in TLV format. for the -decryption process, the blob is retrieved and provisioned into Edge Lock and the -whole factory data can be decrypted using the returned key index in Edge Lock. -Compared with only dac private key protection solution, this solution can avoid -tampering with the original factory data. - -the factory data should be encrypted by an AES-256 key using "--aes256_key" -option in "generate.py" script file. - -it will check whether there is AES key blob in factory data region when in each -initialization, if not, the default AES key is converted and the result is -stored into flash, it run only once. - -for the second one, it only protect the dac private key inside the factory data, -the dac private key is retrieved and provisioned into Edge Lock, the returned -key blob replace the previous dac private key, and also update the overall size -and hash, and re-write the factory data. when device is doing matter -commissioning, the blob is retrieved and provisioned into Edge Lock and the -signing can be done using the returned key index in Edge Lock. - -the factory data should be plain text for the first programming. it will check -whether there is dac private key blob (base on the size of blob, should be 48) -in factory data when in each initialization, if not, the dac private key is -converted and the result is stored into flash, it run only once. - -for the third one, it is a little similar to the first one, the whole factory -data is encrypted by an AES key, but there are two differences: - -- the AES key is hard-coded and not provisioned into Edge Lock -- the factory data should be encrypted by AES-128 key using "--aes128_key" - option in "generate.py" script file. +adding the following gn argument `chip_use_plain_dac_key=true` (not supported on +rw61x). diff --git a/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn b/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn index 73f21538380b0e..5b73da4bc92080 100644 --- a/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn +++ b/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn @@ -1,5 +1,5 @@ # Copyright (c) 2021 Project CHIP Authors -# Copyright 2023 NXP +# Copyright 2023-2024 NXP # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -55,15 +55,6 @@ app_common_folder = "all-clusters-app/all-clusters-common" rt_sdk("sdk") { defines = [] - # To be moved, temporary mbedtls config fix to build app with factory data - if (nxp_enable_secure_dac_private_key_storage || - nxp_enable_secure_whole_factory_data) { - defines += [ - "MBEDTLS_NIST_KW_C", - "MBEDTLS_PSA_CRYPTO_CLIENT", - ] - } - cflags = [] public_deps = [] public_configs = [] @@ -141,8 +132,8 @@ rt_executable("all_cluster_app") { "../../common/main/main.cpp", ] - if (nxp_enable_secure_dac_private_key_storage || - nxp_enable_secure_whole_factory_data) { + if (nxp_enable_secure_whole_factory_data || + nxp_enable_secure_EL2GO_factory_data) { sources += [ "${chip_root}/examples/platform/nxp/${nxp_platform}/factory_data/source/AppFactoryDataExample.cpp" ] if (nxp_enable_secure_whole_factory_data) { defines += [ "ENABLE_SECURE_WHOLE_FACTORY_DATA" ] diff --git a/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn b/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn index 936f1de4a7d262..063cf49b81a2b5 100644 --- a/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn +++ b/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn @@ -56,15 +56,6 @@ app_common_folder = "laundry-washer-app/nxp/zap" rt_sdk("sdk") { defines = [] - # To be moved, temporary mbedtls config fix to build app with factory data - if (nxp_enable_secure_dac_private_key_storage || - nxp_enable_secure_whole_factory_data) { - defines += [ - "MBEDTLS_NIST_KW_C", - "MBEDTLS_PSA_CRYPTO_CLIENT", - ] - } - cflags = [] public_deps = [] public_configs = [] @@ -142,8 +133,8 @@ rt_executable("laundry-washer") { "../../common/main/main.cpp", ] - if (nxp_enable_secure_dac_private_key_storage || - nxp_enable_secure_whole_factory_data) { + if (nxp_enable_secure_whole_factory_data || + nxp_enable_secure_EL2GO_factory_data) { sources += [ "${chip_root}/examples/platform/nxp/${nxp_platform}/factory_data/source/AppFactoryDataExample.cpp" ] if (nxp_enable_secure_whole_factory_data) { defines += [ "ENABLE_SECURE_WHOLE_FACTORY_DATA" ] diff --git a/examples/thermostat/nxp/rt/rw61x/BUILD.gn b/examples/thermostat/nxp/rt/rw61x/BUILD.gn index ec0a6d4f0ec379..07a58e947756c6 100644 --- a/examples/thermostat/nxp/rt/rw61x/BUILD.gn +++ b/examples/thermostat/nxp/rt/rw61x/BUILD.gn @@ -1,5 +1,5 @@ # Copyright (c) 2021 Project CHIP Authors -# Copyright 2023 NXP +# Copyright 2023-2024 NXP # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -58,15 +58,6 @@ app_common_folder = "thermostat/nxp/zap" rt_sdk("sdk") { defines = [] - # To be moved, temporary mbedtls config fix to build app with factory data - if (nxp_enable_secure_dac_private_key_storage || - nxp_enable_secure_whole_factory_data) { - defines += [ - "MBEDTLS_NIST_KW_C", - "MBEDTLS_PSA_CRYPTO_CLIENT", - ] - } - cflags = [] public_deps = [] public_configs = [] @@ -165,8 +156,8 @@ rt_executable("thermostat") { ] } - if (nxp_enable_secure_dac_private_key_storage || - nxp_enable_secure_whole_factory_data) { + if (nxp_enable_secure_whole_factory_data || + nxp_enable_secure_EL2GO_factory_data) { sources += [ "${chip_root}/examples/platform/nxp/${nxp_platform}/factory_data/source/AppFactoryDataExample.cpp" ] if (nxp_enable_secure_whole_factory_data) { defines += [ "ENABLE_SECURE_WHOLE_FACTORY_DATA" ] diff --git a/scripts/tools/nxp/factory_data_generator/custom.py b/scripts/tools/nxp/factory_data_generator/custom.py index 179f990c3052bc..87d3b7dca3c4b7 100644 --- a/scripts/tools/nxp/factory_data_generator/custom.py +++ b/scripts/tools/nxp/factory_data_generator/custom.py @@ -337,3 +337,30 @@ def encode(self): def max_length(self): return 64 + + +class El2GoObject(FileArgument): + + def __init__(self, arg): + super().__init__(arg) + + def key(self): + return 24 + + +class El2GoDacKeyID(IntArgument): + + def __init__(self, arg): + super().__init__(arg) + + def key(self): + return 25 + + +class El2GoDacCertID(IntArgument): + + def __init__(self, arg): + super().__init__(arg) + + def key(self): + return 26 diff --git a/scripts/tools/nxp/factory_data_generator/generate.py b/scripts/tools/nxp/factory_data_generator/generate.py index 945f8bde641749..a36f0153fb8f35 100755 --- a/scripts/tools/nxp/factory_data_generator/generate.py +++ b/scripts/tools/nxp/factory_data_generator/generate.py @@ -23,10 +23,10 @@ import sys from crc import Calculator, Crc16 -from custom import (CertDeclaration, DacCert, DacPKey, Discriminator, HardwareVersion, HardwareVersionStr, IterationCount, - ManufacturingDate, PaiCert, PartNumber, ProductFinish, ProductId, ProductLabel, ProductName, - ProductPrimaryColor, ProductURL, Salt, SerialNum, SetupPasscode, StrArgument, UniqueId, VendorId, VendorName, - Verifier) +from custom import (CertDeclaration, DacCert, DacPKey, Discriminator, El2GoDacCertID, El2GoDacKeyID, El2GoObject, HardwareVersion, + HardwareVersionStr, IterationCount, ManufacturingDate, PaiCert, PartNumber, ProductFinish, ProductId, + ProductLabel, ProductName, ProductPrimaryColor, ProductURL, Salt, SerialNum, SetupPasscode, StrArgument, + UniqueId, VendorId, VendorName, Verifier) from default import InputArgument # Global variable for hash ID @@ -75,13 +75,24 @@ def __init__(self, args): self.spake2p = Spake2p() if self.args.spake2p_verifier is None: self.spake2p.generate(self.args) - self.args.dac_key.generate_private_key(self.args.dac_key_password, self.args.dac_key_use_sss_blob) + if self.args.dac_key: + self.args.dac_key.generate_private_key(self.args.dac_key_password, self.args.dac_key_use_sss_blob) def _validate_args(self): - if self.args.dac_key_password is None: + if self.args.dac_key_password is None and self.args.EL2GO_bin is None: logging.warning( "DAC Key password not provided. It means DAC Key is not protected." ) + if self.args.dac_key and self.args.EL2GO_bin: + logging.error("Could not provide two DAC Key provisionning method at the same time") + + if (not self.args.dac_key or not self.args.dac_cert) and not self.args.EL2GO_bin: + logging.error("Need to provide a DAC provisionner") + raise Exception("Could not generate factory data") + + if self.args.EL2GO_bin and (not self.args.EL2GO_DAC_CERT_ID or not self.args.EL2GO_DAC_KEY_ID): + logging.error("Need to provide EdgeLock 2Go DAC IDs") + raise Exception("Could not generate factory data") str_args = [obj for key, obj in vars(self.args).items() if isinstance(obj, StrArgument)] for str_arg in str_args: @@ -210,10 +221,6 @@ def main(): help="[str] Hardware version as string") required.add_argument("--cert_declaration", required=True, type=CertDeclaration, help="[path] Path to Certification Declaration in DER format") - required.add_argument("--dac_cert", required=True, type=DacCert, - help="[path] Path to DAC certificate in DER format") - required.add_argument("--dac_key", required=True, type=DacPKey, - help="[path] Path to DAC key in DER format") required.add_argument("--pai_cert", required=True, type=PaiCert, help="[path] Path to PAI certificate in DER format") required.add_argument("--spake2p_path", required=True, type=str, @@ -221,6 +228,16 @@ def main(): required.add_argument("--out", required=True, type=str, help="[path] Path to output binary") + optional.add_argument("--dac_cert", type=DacCert, + help="[path] Path to DAC certificate in DER format") + optional.add_argument("--dac_key", type=DacPKey, + help="[path] Path to DAC key in DER format") + optional.add_argument("--EL2GO_bin", type=El2GoObject, + help="[path] Path to EL2GO secure objects binary") + optional.add_argument("--EL2GO_DAC_KEY_ID", type=El2GoDacKeyID, + help="[hex] EL2GO DAC key ID") + optional.add_argument("--EL2GO_DAC_CERT_ID", type=El2GoDacCertID, + help="[hex] EL2GO DAC certificate ID") optional.add_argument("--dac_key_password", type=str, help="[path] Password to decode DAC Key if available") optional.add_argument("--dac_key_use_sss_blob", action='store_true', diff --git a/src/platform/nxp/common/factory_data/FactoryDataProvider.h b/src/platform/nxp/common/factory_data/FactoryDataProvider.h index b06089270a7355..58ad20d7b977fb 100644 --- a/src/platform/nxp/common/factory_data/FactoryDataProvider.h +++ b/src/platform/nxp/common/factory_data/FactoryDataProvider.h @@ -1,7 +1,7 @@ /* * * Copyright (c) 2023 Project CHIP Authors - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,21 @@ namespace chip { namespace DeviceLayer { +#define CHIP_FACTORY_DATA_ERROR(e) \ + ChipError(ChipError::Range::kLastRange, ((uint8_t) ChipError::Range::kLastRange << 2) | e, __FILE__, __LINE__) + +#define CHIP_FACTORY_DATA_SHA_CHECK CHIP_FACTORY_DATA_ERROR(0x01) +#define CHIP_FACTORY_DATA_HEADER_READ CHIP_FACTORY_DATA_ERROR(0x02) +#define CHIP_FACTORY_DATA_HASH_ID CHIP_FACTORY_DATA_ERROR(0x03) +#define CHIP_FACTORY_DATA_PDM_RESTORE CHIP_FACTORY_DATA_ERROR(0x04) +#define CHIP_FACTORY_DATA_NULL CHIP_FACTORY_DATA_ERROR(0x05) +#define CHIP_FACTORY_DATA_FLASH_ERASE CHIP_FACTORY_DATA_ERROR(0x06) +#define CHIP_FACTORY_DATA_FLASH_PROGRAM CHIP_FACTORY_DATA_ERROR(0x07) +#define CHIP_FACTORY_DATA_INTERNAL_FLASH_READ CHIP_FACTORY_DATA_ERROR(0x08) +#define CHIP_FACTORY_DATA_PDM_SAVE_RECORD CHIP_FACTORY_DATA_ERROR(0x09) +#define CHIP_FACTORY_DATA_PDM_READ_RECORD CHIP_FACTORY_DATA_ERROR(0x0A) +#define CHIP_FACTORY_DATA_RESTORE_MECHANISM CHIP_FACTORY_DATA_ERROR(0x0B) + class FactoryDataProviderImpl; /** @@ -72,6 +87,10 @@ class FactoryDataProvider : public chip::Credentials::DeviceAttestationCredentia kProductLabel, kProductFinish, kProductPrimaryColor, + kEl2GoBlob, + kEl2GoDacKeyId, + kEl2GoDacCertId, + kMaxId }; diff --git a/src/platform/nxp/rt/rw61x/BUILD.gn b/src/platform/nxp/rt/rw61x/BUILD.gn index 13c2b3c2ffc591..684faf3a7f575c 100644 --- a/src/platform/nxp/rt/rw61x/BUILD.gn +++ b/src/platform/nxp/rt/rw61x/BUILD.gn @@ -1,5 +1,5 @@ # Copyright (c) 2021 Project CHIP Authors -# Copyright 2023 NXP +# Copyright 2023-2024 NXP # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -52,18 +52,18 @@ config("nxp_platform_config") { "CONFIG_CHIP_ENCRYPTED_FACTORY_DATA=1", ] - if (nxp_enable_secure_dac_private_key_storage) { - assert(nxp_enable_secure_dac_private_key_storage && - !nxp_enable_secure_whole_factory_data, - "please select only one protection solution") - defines += [ "EXTERNAL_FACTORY_DATA_PROVIDER_IMPL_HEADER=\"platform/nxp/rt/rw61x/FactoryDataProviderImpl.h\"" ] - } else if (nxp_enable_secure_whole_factory_data) { + if (nxp_enable_secure_whole_factory_data) { assert(nxp_enable_secure_whole_factory_data && - !nxp_enable_secure_dac_private_key_storage, + !nxp_enable_secure_EL2GO_factory_data, "please select only one protection solution") defines += [ "EXTERNAL_FACTORY_DATA_PROVIDER_IMPL_HEADER=\"platform/nxp/rt/rw61x/FactoryDataProviderEncImpl.h\"" ] + } else if (nxp_enable_secure_EL2GO_factory_data) { + assert(!nxp_enable_secure_whole_factory_data && + nxp_enable_secure_EL2GO_factory_data, + "please select only one protection solution") + defines += [ "EXTERNAL_FACTORY_DATA_PROVIDER_IMPL_HEADER=\"platform/nxp/rt/rw61x/FactoryDataProviderEl2GoImpl.h\"" ] } else { - defines += [ "EXTERNAL_FACTORY_DATA_PROVIDER_IMPL_HEADER=\"platform/nxp/common/factory_data/FactoryDataProviderFwkImpl.h\"" ] + defines += [ "EXTERNAL_FACTORY_DATA_PROVIDER_IMPL_HEADER=\"platform/nxp/rt/rw61x/FactoryDataProviderImpl.h\"" ] } } @@ -201,20 +201,20 @@ static_library("nxp_platform") { "../../common/factory_data/FactoryDataProvider.cpp", "../../common/factory_data/FactoryDataProvider.h", ] - if (nxp_enable_secure_dac_private_key_storage) { - sources += [ - "FactoryDataProviderImpl.cpp", - "FactoryDataProviderImpl.h", - ] - } else if (nxp_enable_secure_whole_factory_data) { + if (nxp_enable_secure_whole_factory_data) { sources += [ "FactoryDataProviderEncImpl.cpp", "FactoryDataProviderEncImpl.h", ] + } else if (nxp_enable_secure_EL2GO_factory_data) { + sources += [ + "FactoryDataProviderEl2GoImpl.cpp", + "FactoryDataProviderEl2GoImpl.h", + ] } else { sources += [ - "../../common/factory_data/FactoryDataProviderFwkImpl.cpp", - "../../common/factory_data/FactoryDataProviderFwkImpl.h", + "FactoryDataProviderImpl.cpp", + "FactoryDataProviderImpl.h", ] } diff --git a/src/platform/nxp/rt/rw61x/FactoryDataProviderEl2GoImpl.cpp b/src/platform/nxp/rt/rw61x/FactoryDataProviderEl2GoImpl.cpp new file mode 100644 index 00000000000000..d7919201af7ca4 --- /dev/null +++ b/src/platform/nxp/rt/rw61x/FactoryDataProviderEl2GoImpl.cpp @@ -0,0 +1,283 @@ +/* + * + * Copyright (c) 2020-2022 Project CHIP Authors + * Copyright 2024 NXP + * + * 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 "FactoryDataProviderEl2GoImpl.h" + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +#include "ELSFactoryData.h" +#include "mflash_drv.h" + +#if defined(MBEDTLS_THREADING_C) && defined(MBEDTLS_THREADING_ALT) +#include "els_pkc_mbedtls.h" +#endif /* defined(MBEDTLS_THREADING_C) && defined(MBEDTLS_THREADING_ALT) */ + +#include "fsl_adapter_flash.h" + +/* mbedtls */ +#include "mbedtls/aes.h" +#include "mbedtls/sha256.h" + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#ifndef FACTORY_DATA_PROVIDER_LOG +#define FACTORY_DATA_PROVIDER_LOG 0 +#endif + +#if FACTORY_DATA_PROVIDER_LOG +#include "fsl_debug_console.h" +#define FACTORY_DATA_PROVIDER_PRINTF(...) \ + PRINTF("[%s] ", __FUNCTION__); \ + PRINTF(__VA_ARGS__); \ + PRINTF("\n\r"); +#else +#define FACTORY_DATA_PROVIDER_PRINTF(...) +#endif + +/* Grab symbol for the base address from the linker file. */ +extern uint32_t __FACTORY_DATA_START_OFFSET[]; +extern uint32_t __FACTORY_DATA_SIZE[]; + +using namespace ::chip::Credentials; +using namespace ::chip::Crypto; + +namespace chip { +namespace DeviceLayer { + +FactoryDataProviderImpl FactoryDataProviderImpl::sInstance; + +CHIP_ERROR FactoryDataProviderImpl::SearchForId(uint8_t searchedType, uint8_t * pBuf, size_t bufLength, uint16_t & length, + uint32_t * contentAddr) +{ + CHIP_ERROR err = CHIP_ERROR_NOT_FOUND; + uint8_t type = 0; + uint32_t index = 0; + uint8_t * addrContent = NULL; + uint8_t * factoryDataAddress = &factoryDataRamBuffer[0]; + uint32_t factoryDataSize = sizeof(factoryDataRamBuffer); + uint16_t currentLen = 0; + + while (index < factoryDataSize) + { + /* Read the type */ + memcpy((uint8_t *) &type, factoryDataAddress + index, sizeof(type)); + index += sizeof(type); + + /* Read the len */ + memcpy((uint8_t *) ¤tLen, factoryDataAddress + index, sizeof(currentLen)); + index += sizeof(currentLen); + + /* Check if the type gotten is the expected one */ + if (searchedType == type) + { + FACTORY_DATA_PROVIDER_PRINTF("type = %d, currentLen = %d, bufLength =%d", type, currentLen, bufLength); + /* If pBuf is null it means that we only want to know if the Type has been found */ + if (pBuf != NULL) + { + /* If the buffer given is too small, fill only the available space */ + if (bufLength < currentLen) + { + currentLen = bufLength; + } + memcpy((uint8_t *) pBuf, factoryDataAddress + index, currentLen); + } + length = currentLen; + if (contentAddr != NULL) + { + *contentAddr = (uint32_t) factoryDataAddress + index; + } + err = CHIP_NO_ERROR; + break; + } + else if (type == 0) + { + /* No more type available , break the loop */ + break; + } + else + { + /* Jump to next data */ + index += currentLen; + } + } + + return err; +} + +CHIP_ERROR FactoryDataProviderImpl::GetDeviceAttestationCert(MutableByteSpan & outBuffer) +{ + status_t status = STATUS_SUCCESS; + uint8_t el2go_blob[EL2GO_MAX_BLOB_SIZE] = { 0U }; + size_t el2go_blob_size = 0U; + size_t outBufferSize = 0U; + uint16_t CertificateIdSize = 0; + uint16_t BlobSize = 0; + uint32_t Addr; + uint32_t el2go_dac_cert_id = 0; + + /* Search key ID FactoryDataId::kEl2GoBlob address */ + ReturnErrorOnFailure(SearchForId(FactoryDataId::kEl2GoBlob, NULL, 0, BlobSize, &Addr)); + ReturnErrorOnFailure( + SearchForId(FactoryDataId::kEl2GoDacCertId, (uint8_t *) &el2go_dac_cert_id, sizeof(el2go_dac_cert_id), CertificateIdSize)); + + /* Read DAC certificate from EL2GO data */ + status = + read_el2go_blob((uint8_t *) Addr, (size_t) BlobSize, el2go_dac_cert_id, el2go_blob, EL2GO_MAX_BLOB_SIZE, &el2go_blob_size); + + STATUS_SUCCESS_OR_EXIT_MSG("DAC Private key not found: 0x%08x", status); + + // Import EL2GO blobs in ELS + status = decrypt_el2go_cert_blob(el2go_blob, el2go_blob_size, outBuffer.data(), outBuffer.size(), &outBufferSize); + outBuffer.reduce_size(outBufferSize); + STATUS_SUCCESS_OR_EXIT_MSG("decrypt_el2go_cert_blob failed: 0x%08x", status); + + return CHIP_NO_ERROR; + +exit: + return CHIP_ERROR_INTERNAL; +} + +CHIP_ERROR FactoryDataProviderImpl::ReadAndCheckFactoryDataInFlash(void) +{ + status_t status; + uint32_t factoryDataAddress = (uint32_t) __FACTORY_DATA_START_OFFSET; + uint32_t factoryDataSize = (uint32_t) __FACTORY_DATA_SIZE; + uint32_t hashId; + uint8_t calculatedHash[SHA256_OUTPUT_SIZE]; + CHIP_ERROR res; + + /* Init mflash */ + status = mflash_drv_init(); + + if (status != kStatus_Success || factoryDataSize > sizeof(factoryDataRamBuffer)) + return CHIP_ERROR_INTERNAL; + + /* Load the factory data into RAM buffer */ + if (mflash_drv_read(factoryDataAddress, (uint32_t *) &factoryDataRamBuffer[0], factoryDataSize) != kStatus_Success) + { + return CHIP_ERROR_INTERNAL; + } + memcpy(&mHeader, factoryDataRamBuffer, sizeof(mHeader)); + if (mHeader.hashId != HASH_ID) + { + return CHIP_FACTORY_DATA_HASH_ID; + } + /* remove the header section */ + memmove(&factoryDataRamBuffer[0], &factoryDataRamBuffer[sizeof(mHeader)], mHeader.size); + + /* Calculate SHA256 value over the factory data and compare with stored value */ + res = Hash_SHA256(&factoryDataRamBuffer[0], mHeader.size, &calculatedHash[0]); + + if (res != CHIP_NO_ERROR) + return res; + + if (memcmp(&calculatedHash[0], &mHeader.hash[0], HASH_LEN) != 0) + { + return CHIP_FACTORY_DATA_HASH_ID; + } + + ChipLogProgress(DeviceLayer, "factory data hash check is successful!"); + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & digestToSign, MutableByteSpan & outSignBuffer) +{ + CHIP_ERROR res = CHIP_NO_ERROR; + status_t status = STATUS_SUCCESS; + uint8_t el2go_blob[EL2GO_MAX_BLOB_SIZE] = { 0U }; + size_t el2go_blob_size = 0U; + mcuxClEls_EccSignOption_t sign_options = { 0 }; + uint8_t public_key[MCUXCLELS_ECC_PUBLICKEY_SIZE] = { 0 }; + size_t public_key_size = sizeof(public_key); + uint8_t hash[MCUXCLHASH_OUTPUT_SIZE_SHA_256] = { 0 }; + mcuxClEls_KeyIndex_t key_index = MCUXCLELS_KEY_SLOTS; + mcuxClEls_EccByte_t ecc_signature[MCUXCLELS_ECC_SIGNATURE_SIZE]; + uint8_t digest[kSHA256_Hash_Length]; + uint16_t BlobSize = 0; + uint16_t KeyIdSize = 0; + uint32_t Addr; + uint32_t el2go_dac_key_id = 0; + + /* Search key ID FactoryDataId::kEl2GoBlob */ + ReturnErrorOnFailure(SearchForId(FactoryDataId::kEl2GoBlob, NULL, 0, BlobSize, &Addr)); + ReturnErrorOnFailure( + SearchForId(FactoryDataId::kEl2GoDacKeyId, (uint8_t *) &el2go_dac_key_id, sizeof(el2go_dac_key_id), KeyIdSize)); + + /* Calculate message HASH to sign */ + memset(&digest[0], 0, sizeof(digest)); + res = Hash_SHA256(digestToSign.data(), digestToSign.size(), &digest[0]); + if (res != CHIP_NO_ERROR) + { + return res; + } + +#if defined(MBEDTLS_THREADING_C) && defined(MBEDTLS_THREADING_ALT) + (void) mcux_els_mutex_lock(); +#endif + + /* Read DAC key from EL2GO data*/ + status = + read_el2go_blob((uint8_t *) Addr, (size_t) BlobSize, el2go_dac_key_id, el2go_blob, EL2GO_MAX_BLOB_SIZE, &el2go_blob_size); + STATUS_SUCCESS_OR_EXIT_MSG("DAC Provate key not found: 0x%08x", status); + + // Import EL2GO blobs in ELS + status = import_el2go_key_in_els(el2go_blob, el2go_blob_size, &key_index); + + // Generate key in ELS + status = els_keygen(key_index, public_key, &public_key_size); + STATUS_SUCCESS_OR_EXIT_MSG("els_keygen failed: 0x%08x", status); + + // Compute signature + status = ELS_sign_hash(hash, ecc_signature, &sign_options, key_index); + CopySpanToMutableSpan(ByteSpan{ ecc_signature, MCUXCLELS_ECC_SIGNATURE_SIZE }, outSignBuffer); + STATUS_SUCCESS_OR_EXIT_MSG("ELS_sign_hash failed: 0x%08x", status); + + status = els_delete_key(key_index); + STATUS_SUCCESS_OR_EXIT_MSG("Deletion of el2goimport_auth failed", status); + +#if defined(MBEDTLS_THREADING_C) && defined(MBEDTLS_THREADING_ALT) + (void) mcux_els_mutex_unlock(); +#endif + return CHIP_NO_ERROR; +exit: +#if defined(MBEDTLS_THREADING_C) && defined(MBEDTLS_THREADING_ALT) + (void) mcux_els_mutex_unlock(); +#endif + return CHIP_ERROR_INTERNAL; +} + +CHIP_ERROR FactoryDataProviderImpl::Init(void) +{ + uint16_t len; + uint8_t type; + uint16_t keySize = 0; + status_t status = STATUS_SUCCESS; + + ReturnLogErrorOnFailure(ReadAndCheckFactoryDataInFlash()); + + els_enable(); + + return CHIP_NO_ERROR; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/rt/rw61x/FactoryDataProviderEl2GoImpl.h b/src/platform/nxp/rt/rw61x/FactoryDataProviderEl2GoImpl.h new file mode 100644 index 00000000000000..fdf3aa9b80a540 --- /dev/null +++ b/src/platform/nxp/rt/rw61x/FactoryDataProviderEl2GoImpl.h @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2020-2022 Project CHIP Authors + * Copyright 2024 NXP + * + * 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 + +#define FACTORY_DATA_MAX_SIZE 4096 + +#define EL2GO_MAX_BLOB_SIZE 3072U +#define EL2GO_MAX_CERT_SIZE 2048U +#define PUBLIC_KEY_SIZE 64U + +namespace chip { +namespace DeviceLayer { + +/** + * @brief This class provides Commissionable data and Device Attestation Credentials. + * + * This implementation allows to use the ELS hardware module to load the Matter factory + * dataset in RAM at the boot. + * + * + */ + +class FactoryDataProviderImpl : public FactoryDataProvider +{ +public: + static FactoryDataProviderImpl sInstance; + + CHIP_ERROR Init(void); + CHIP_ERROR SearchForId(uint8_t searchedType, uint8_t * pBuf, size_t bufLength, uint16_t & length, + uint32_t * contentAddr = NULL); + CHIP_ERROR SignWithDacKey(const ByteSpan & digestToSign, MutableByteSpan & outSignBuffer); + ; + CHIP_ERROR GetDeviceAttestationCert(MutableByteSpan & outBuffer) override; + +private: + struct Header + { + uint32_t hashId; + uint32_t size; + uint8_t hash[4]; + }; + uint8_t factoryDataRamBuffer[FACTORY_DATA_MAX_SIZE]; + Header mHeader; + + CHIP_ERROR ReadAndCheckFactoryDataInFlash(void); +}; + +inline FactoryDataProvider & FactoryDataPrvd() +{ + return FactoryDataProviderImpl::sInstance; +} + +inline FactoryDataProviderImpl & FactoryDataPrvdImpl() +{ + return FactoryDataProviderImpl::sInstance; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.cpp b/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.cpp index 73155af65eb48c..4fcd61c02d1ecf 100644 --- a/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.cpp +++ b/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.cpp @@ -1,7 +1,7 @@ /* * * Copyright (c) 2020-2022 Project CHIP Authors - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,10 @@ extern "C" { #include "ELSFactoryData.h" #include "mflash_drv.h" +#if defined(MBEDTLS_THREADING_C) && defined(MBEDTLS_THREADING_ALT) +#include "els_pkc_mbedtls.h" +#endif /* defined(MBEDTLS_THREADING_C) && defined(MBEDTLS_THREADING_ALT) */ + #include "fsl_adapter_flash.h" /* mbedtls */ @@ -63,6 +67,23 @@ FactoryDataProviderImpl FactoryDataProviderImpl::sInstance; static constexpr size_t kPrivateKeyBlobLength = Crypto::kP256_PrivateKey_Length + ELS_BLOB_METADATA_SIZE + ELS_WRAP_OVERHEAD; +CHIP_ERROR FactoryDataProviderImpl::DecryptAes128Ecb(uint8_t * dest, uint8_t * source, const uint8_t * aes128Key) +{ + uint8_t res = 0; + mbedtls_aes_context aesCtx; + + mbedtls_aes_init(&aesCtx); + res = mbedtls_aes_setkey_dec(&aesCtx, aes128Key, 128U); + VerifyOrReturnError(res == 0, CHIP_ERROR_INTERNAL); + + res = mbedtls_aes_crypt_ecb(&aesCtx, MBEDTLS_AES_DECRYPT, source, dest); + VerifyOrReturnError(res == 0, CHIP_ERROR_INTERNAL); + + mbedtls_aes_free(&aesCtx); + + return CHIP_NO_ERROR; +} + CHIP_ERROR FactoryDataProviderImpl::SearchForId(uint8_t searchedType, uint8_t * pBuf, size_t bufLength, uint16_t & length, uint32_t * contentAddr) { @@ -123,6 +144,7 @@ CHIP_ERROR FactoryDataProviderImpl::SearchForId(uint8_t searchedType, uint8_t * CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & digestToSign, MutableByteSpan & outSignBuffer) { + CHIP_ERROR res = CHIP_NO_ERROR; uint8_t els_key_blob[kPrivateKeyBlobLength]; size_t els_key_blob_size = sizeof(els_key_blob); uint16_t keySize = 0; @@ -146,6 +168,19 @@ CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & digestToSign PLOG_DEBUG_BUFFER("els_key_blob", els_key_blob, els_key_blob_size); + /* Calculate message HASH to sign */ + memset(&digest[0], 0, sizeof(digest)); + res = Hash_SHA256(digestToSign.data(), digestToSign.size(), &digest[0]); + if (res != CHIP_NO_ERROR) + { + return res; + } + + PLOG_DEBUG_BUFFER("digestToSign", digestToSign.data(), digestToSign.size()); + +#if defined(MBEDTLS_THREADING_C) && defined(MBEDTLS_THREADING_ALT) + (void) mcux_els_mutex_lock(); +#endif /* Import blob DAC key into SE50 (reserved key slot) */ status = import_die_int_wrapped_key_into_els(els_key_blob, els_key_blob_size, plain_key_properties, &key_index); STATUS_SUCCESS_OR_EXIT_MSG("import_die_int_wrapped_key_into_els failed: 0x%08x", status); @@ -160,12 +195,6 @@ CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & digestToSign /* The key is usable for signing. */ PLOG_DEBUG_BUFFER("public_key", public_key, public_key_size); - /* Calculate message HASH to sign */ - memset(&digest[0], 0, sizeof(digest)); - ReturnErrorOnFailure(Hash_SHA256(digestToSign.data(), digestToSign.size(), &digest[0])); - - PLOG_DEBUG_BUFFER("digestToSign", digestToSign.data(), digestToSign.size()); - /* ECC sign message hash with the key index slot reserved during the blob importation */ ELS_sign_hash(digest, ecc_signature, &sign_options, key_index); @@ -173,10 +202,16 @@ CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & digestToSign els_delete_key(key_index); /* Generate MutableByteSpan with ECC signature and ECC signature size */ +#if defined(MBEDTLS_THREADING_C) && defined(MBEDTLS_THREADING_ALT) + (void) mcux_els_mutex_unlock(); +#endif return CopySpanToMutableSpan(ByteSpan{ ecc_signature, MCUXCLELS_ECC_SIGNATURE_SIZE }, outSignBuffer); exit: els_delete_key(key_index); +#if defined(MBEDTLS_THREADING_C) && defined(MBEDTLS_THREADING_ALT) + (void) mcux_els_mutex_unlock(); +#endif return CHIP_ERROR_INVALID_SIGNATURE; } @@ -188,6 +223,7 @@ CHIP_ERROR FactoryDataProviderImpl::ReadAndCheckFactoryDataInFlash(void) uint32_t hashId; uint8_t calculatedHash[SHA256_OUTPUT_SIZE]; CHIP_ERROR res; + uint8_t currentBlock[16]; /* Init mflash */ status = mflash_drv_init(); @@ -216,13 +252,64 @@ CHIP_ERROR FactoryDataProviderImpl::ReadAndCheckFactoryDataInFlash(void) if (memcmp(&calculatedHash[0], &mHeader.hash[0], HASH_LEN) != 0) { - return CHIP_ERROR_NOT_FOUND; + /* HASH value didn't match, test if factory data are encrypted */ + + /* try to decrypt factory data, reset factory data buffer content*/ + memset(factoryDataRamBuffer, 0, sizeof(factoryDataRamBuffer)); + memset(calculatedHash, 0, sizeof(calculatedHash)); + + factoryDataAddress += sizeof(Header); + + /* Load the buffer into RAM by reading each 16 bytes blocks */ + for (int i = 0; i < (mHeader.size / 16); i++) + { + if (mflash_drv_read(factoryDataAddress + i * 16, (uint32_t *) ¤tBlock[0], sizeof(currentBlock)) != + kStatus_Success) + { + return CHIP_ERROR_INTERNAL; + } + ReturnErrorOnFailure(DecryptAes128Ecb(&factoryDataRamBuffer[i * 16], ¤tBlock[0], pAesKey)); + } + + /* Calculate SHA256 value over the factory data and compare with stored value */ + res = Hash_SHA256(&factoryDataRamBuffer[0], mHeader.size, &calculatedHash[0]); + if (memcmp(&calculatedHash[0], &mHeader.hash[0], HASH_LEN) != 0) + { + return CHIP_ERROR_NOT_FOUND; + } } ChipLogProgress(DeviceLayer, "factory data hash check is successful!"); return CHIP_NO_ERROR; } +CHIP_ERROR FactoryDataProviderImpl::SetAes128Key(const uint8_t * keyAes128) +{ + CHIP_ERROR error = CHIP_ERROR_INVALID_ARGUMENT; + if (keyAes128 != nullptr) + { + pAesKey = keyAes128; + error = CHIP_NO_ERROR; + } + return error; +} + +CHIP_ERROR FactoryDataProviderImpl::SetEncryptionMode(EncryptionMode mode) +{ + CHIP_ERROR error = CHIP_ERROR_INVALID_ARGUMENT; + + /* + * Currently the fwk_factory_data_provider module supports only ecb mode. + * Therefore return an error if encrypt mode is not ecb + */ + if (mode == encrypt_ecb) + { + encryptMode = mode; + error = CHIP_NO_ERROR; + } + return error; +} + CHIP_ERROR FactoryDataProviderImpl::Init(void) { uint16_t len; @@ -250,11 +337,6 @@ CHIP_ERROR FactoryDataProviderImpl::Init(void) ChipLogProgress(DeviceLayer, "SSS: convert DAC private key to blob"); ReturnLogErrorOnFailure(ELS_ConvertDacKey()); ChipLogProgress(DeviceLayer, "System restarting"); - // Restart the system. - NVIC_SystemReset(); - while (1) - { - } } return CHIP_NO_ERROR; @@ -278,8 +360,8 @@ CHIP_ERROR FactoryDataProviderImpl::ELS_ConvertDacKey() PLOG_DEBUG_BUFFER("blob", blob, blobSize); /* Read all factory data */ - hal_flash_status_t status = - HAL_FlashRead(factoryDataAddress + MFLASH_BASE_ADDRESS, newSize - (ELS_BLOB_METADATA_SIZE + ELS_WRAP_OVERHEAD), data); + hal_flash_status_t status = HAL_FlashRead(factoryDataAddress + MFLASH_BASE_ADDRESS, sizeof(Header), data); + memcpy(data + sizeof(Header), factoryDataRamBuffer, mHeader.size); VerifyOrReturnError(status == kStatus_HAL_Flash_Success, CHIP_ERROR_INTERNAL); ChipLogError(DeviceLayer, "SSS: cached factory data in RAM"); @@ -296,6 +378,13 @@ CHIP_ERROR FactoryDataProviderImpl::ELS_ConvertDacKey() VerifyOrReturnError(status == kStatus_HAL_Flash_Success, CHIP_ERROR_INTERNAL); ChipLogError(DeviceLayer, "SSS: updated factory data"); + /* remove the header section as it will no longer be used */ + memmove(&data[0], &data[sizeof(mHeader)], newSize); + memset(factoryDataRamBuffer, 0, sizeof(factoryDataRamBuffer)); + memcpy(factoryDataRamBuffer, data, newSize); + /* Actualisation of the factory data payload size */ + mHeader.size = newSize; + chip::Platform::MemoryFree(data); return CHIP_NO_ERROR; } diff --git a/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.h b/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.h index 4fc4785328aaf4..4e72fcd9539d65 100644 --- a/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.h +++ b/src/platform/nxp/rt/rw61x/FactoryDataProviderImpl.h @@ -1,7 +1,7 @@ /* * * Copyright (c) 2020-2022 Project CHIP Authors - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,6 +44,9 @@ class FactoryDataProviderImpl : public FactoryDataProvider uint32_t * contentAddr = NULL); CHIP_ERROR SignWithDacKey(const ByteSpan & digestToSign, MutableByteSpan & outSignBuffer); + CHIP_ERROR SetAes128Key(const uint8_t * keyAes128); + CHIP_ERROR SetEncryptionMode(EncryptionMode mode); + private: struct Header { @@ -54,6 +57,9 @@ class FactoryDataProviderImpl : public FactoryDataProvider uint8_t factoryDataRamBuffer[FACTORY_DATA_MAX_SIZE]; Header mHeader; + const uint8_t * pAesKey = nullptr; + EncryptionMode encryptMode = encrypt_ecb; + /* TLV offset */ static constexpr uint32_t kLengthOffset = 1; static constexpr uint32_t kValueOffset = 3; @@ -61,6 +67,7 @@ class FactoryDataProviderImpl : public FactoryDataProvider CHIP_ERROR ReplaceWithBlob(uint8_t * data, uint8_t * blob, size_t blobLen, uint32_t offset); CHIP_ERROR ELS_ExportBlob(uint8_t * data, size_t * dataLen, uint32_t & offset); CHIP_ERROR ELS_ConvertDacKey(); + CHIP_ERROR DecryptAes128Ecb(uint8_t * dest, uint8_t * source, const uint8_t * aes128Key); CHIP_ERROR ReadAndCheckFactoryDataInFlash(void); }; diff --git a/third_party/nxp/nxp_matter_support b/third_party/nxp/nxp_matter_support index 69f40517ca5f27..7323d61dfc746a 160000 --- a/third_party/nxp/nxp_matter_support +++ b/third_party/nxp/nxp_matter_support @@ -1 +1 @@ -Subproject commit 69f40517ca5f27fdf3026f695c0d0607b604dc0e +Subproject commit 7323d61dfc746aff677cb40c17cfed9d43dd9c1d From dee82ef764576aef07ad18b59486b7604c44d936 Mon Sep 17 00:00:00 2001 From: Amine Alami <43780877+Alami-Amine@users.noreply.github.com> Date: Tue, 26 Nov 2024 20:45:18 +0100 Subject: [PATCH 02/26] Make IsInitialized implementation in OpenSSL backward compatible with older OpenSSL versions (#36634) --- src/crypto/CHIPCryptoPALOpenSSL.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/crypto/CHIPCryptoPALOpenSSL.cpp b/src/crypto/CHIPCryptoPALOpenSSL.cpp index e1a8acb55fe5d5..9f2592a12aee0c 100644 --- a/src/crypto/CHIPCryptoPALOpenSSL.cpp +++ b/src/crypto/CHIPCryptoPALOpenSSL.cpp @@ -479,11 +479,13 @@ bool Hash_SHA256_stream::IsInitialized() EVP_MD_CTX * mdctx = to_inner_hash_evp_md_ctx(&mContext); VerifyOrReturnValue(mdctx != nullptr, false); -// Verify that the EVP_MD_CTX is initialized to SHA256 (ensures that EVP_DigestInit_ex was called) -#if CHIP_CRYPTO_BORINGSSL +// Verify that the EVP_MD_CTX is initialized to SHA256 (ensures that EVP_DigestInit_ex was successfully called). +// The legacy API EVP_MD_CTX_md() to check SHA256 initialization is deprecated in OpenSSL 3.0 +// and was replaced by EVP_MD_CTX_get0_md(). +// OpenSSL 1.1.1, which BoringSSL also uses at the time of this comment, does not support the newer replacement API. +#if CHIP_CRYPTO_BORINGSSL || (defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x30000000L) return EVP_MD_CTX_md(mdctx) == _digestForType(DigestType::SHA256); #else - // EVP_MD_CTX_md() was Deprecated in OPENSSL 3.0; However, BoringSSL does not support EVP_MD_CTX_get0_md() yet return EVP_MD_CTX_get0_md(mdctx) == _digestForType(DigestType::SHA256); #endif } From e75d6da10bfcd7bab7d4e99529bdd30b43420114 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 26 Nov 2024 15:07:59 -0500 Subject: [PATCH 03/26] Add some additional `dataModelProvider` settings on server init (#36639) * Add some missed registrations of dataModelProvider in server init * Fix commissioner main dependencies (make nrf tests compile) * Move around dependencies - apparently the commissioner main should be public * Fix one more odd dependency --- examples/common/tracing/BUILD.gn | 2 +- examples/lighting-app/nrfconnect/main/AppTask.cpp | 2 ++ examples/lighting-app/qpg/src/AppTask.cpp | 2 ++ examples/ota-requestor-app/ameba/main/chipinterface.cpp | 4 +++- examples/platform/linux/BUILD.gn | 3 +-- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/common/tracing/BUILD.gn b/examples/common/tracing/BUILD.gn index 9a1193060058db..6e3bb1277aedff 100644 --- a/examples/common/tracing/BUILD.gn +++ b/examples/common/tracing/BUILD.gn @@ -79,7 +79,6 @@ source_set("trace_handlers") { source_set("trace_handlers_decoder") { sources = [ "TraceDecoder.cpp", - "TraceHandlers.cpp", "decoder/TraceDecoderProtocols.cpp", "decoder/bdx/Decoder.cpp", "decoder/echo/Decoder.cpp", @@ -94,6 +93,7 @@ source_set("trace_handlers_decoder") { public_configs = [ ":default_config" ] deps = [ + ":trace_handlers", "${chip_root}/src/lib", "${chip_root}/src/lib/core:types", ] diff --git a/examples/lighting-app/nrfconnect/main/AppTask.cpp b/examples/lighting-app/nrfconnect/main/AppTask.cpp index 014849780caf06..b8464779d73f12 100644 --- a/examples/lighting-app/nrfconnect/main/AppTask.cpp +++ b/examples/lighting-app/nrfconnect/main/AppTask.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -262,6 +263,7 @@ CHIP_ERROR AppTask::Init() initParams.operationalKeystore = &sPSAOperationalKeystore; #endif (void) initParams.InitializeStaticResourcesBeforeServerInit(); + initParams.dataModelProvider = CodegenDataModelProviderInstance(); initParams.testEventTriggerDelegate = &sTestEventTriggerDelegate; ReturnErrorOnFailure(chip::Server::GetInstance().Init(initParams)); AppFabricTableDelegate::Init(); diff --git a/examples/lighting-app/qpg/src/AppTask.cpp b/examples/lighting-app/qpg/src/AppTask.cpp index 0c09e97a6a5681..1047968ffe6f9d 100644 --- a/examples/lighting-app/qpg/src/AppTask.cpp +++ b/examples/lighting-app/qpg/src/AppTask.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -273,6 +274,7 @@ void AppTask::InitServer(intptr_t arg) VerifyOrDie(sTestEventTriggerDelegate.Init(ByteSpan(sTestEventTriggerEnableKey)) == CHIP_NO_ERROR); VerifyOrDie(sTestEventTriggerDelegate.AddHandler(&sFaultTestEventTriggerHandler) == CHIP_NO_ERROR); (void) initParams.InitializeStaticResourcesBeforeServerInit(); + initParams.dataModelProvider = CodegenDataModelProviderInstance(); initParams.testEventTriggerDelegate = &sTestEventTriggerDelegate; chip::Server::GetInstance().Init(initParams); diff --git a/examples/ota-requestor-app/ameba/main/chipinterface.cpp b/examples/ota-requestor-app/ameba/main/chipinterface.cpp index 6d0af83d5c8daf..115441a2f9fd92 100644 --- a/examples/ota-requestor-app/ameba/main/chipinterface.cpp +++ b/examples/ota-requestor-app/ameba/main/chipinterface.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -78,7 +79,8 @@ static void InitServer(intptr_t context) static chip::CommonCaseDeviceServerInitParams initParams; (void) initParams.InitializeStaticResourcesBeforeServerInit(); static AmebaObserver sAmebaObserver; - initParams.appDelegate = &sAmebaObserver; + initParams.dataModelProvider = CodegenDataModelProviderInstance(); + initParams.appDelegate = &sAmebaObserver; chip::Server::GetInstance().Init(initParams); gExampleDeviceInfoProvider.SetStorageDelegate(&Server::GetInstance().GetPersistentStorage()); chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider); diff --git a/examples/platform/linux/BUILD.gn b/examples/platform/linux/BUILD.gn index 1d4f191cb8263e..478b9960cd8c77 100644 --- a/examples/platform/linux/BUILD.gn +++ b/examples/platform/linux/BUILD.gn @@ -74,8 +74,6 @@ source_set("app-main") { "AppMain.h", "CommissionableInit.cpp", "CommissionableInit.h", - "CommissionerMain.cpp", - "CommissionerMain.h", "LinuxCommissionableDataProvider.cpp", "LinuxCommissionableDataProvider.h", "NamedPipeCommands.cpp", @@ -90,6 +88,7 @@ source_set("app-main") { public_deps = [ ":boolean-state-configuration-test-event-trigger", + ":commissioner-main", ":device-energy-management-test-event-trigger", ":energy-evse-test-event-trigger", ":energy-reporting-test-event-trigger", From ffbc362200b60380114a3e136a44343c0de5e64d Mon Sep 17 00:00:00 2001 From: Karsten Sperling <113487422+ksperling-apple@users.noreply.github.com> Date: Wed, 27 Nov 2024 10:23:34 +1300 Subject: [PATCH 04/26] Resolve CommissionerMain dependency issues (#36632) * Resolve CommissionerMain dependency issues Note that CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE=1 requires chip_build_controller=true at the GN level, otherwise `lib` does not pull in `controller`. * Touch something in /tests/ to force NRF native_posix_64 tests to run * Add nogncheck to conditional controller imports --- examples/platform/linux/CommissionerMain.cpp | 20 ++++++++--------- examples/platform/linux/CommissionerMain.h | 23 ++++++++------------ src/app/tests/BUILD.gn | 7 +++--- 3 files changed, 21 insertions(+), 29 deletions(-) diff --git a/examples/platform/linux/CommissionerMain.cpp b/examples/platform/linux/CommissionerMain.cpp index 54ad104c012e4b..f54cfc4bd15d3b 100644 --- a/examples/platform/linux/CommissionerMain.cpp +++ b/examples/platform/linux/CommissionerMain.cpp @@ -16,10 +16,7 @@ * limitations under the License. */ -#include -#include - -#include +#include "CommissionerMain.h" #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE @@ -31,6 +28,7 @@ #include #include #include +#include #include #include @@ -48,23 +46,23 @@ #include #include +#include #include #include #include +#include +#include #include -#include -#include -#include -#include +#include // nogncheck +#include // nogncheck #if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED #include "TraceHandlers.h" #endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED #include - -#include "CommissionerMain.h" +#include using namespace chip; using namespace chip::Credentials; @@ -459,7 +457,7 @@ CommissionerDiscoveryController * GetCommissionerDiscoveryController() return &gCommissionerDiscoveryController; } -SessionKeystore * GetSessionKeystore() +Crypto::SessionKeystore * GetSessionKeystore() { return &gSessionKeystore; } diff --git a/examples/platform/linux/CommissionerMain.h b/examples/platform/linux/CommissionerMain.h index 106e94b0edcb31..64855b55708086 100644 --- a/examples/platform/linux/CommissionerMain.h +++ b/examples/platform/linux/CommissionerMain.h @@ -18,20 +18,15 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include +#include #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE -using chip::PersistentStorageDelegate; -using chip::Controller::DeviceCommissioner; -using chip::Crypto::SessionKeystore; -using chip::Transport::PeerAddress; +#include // nogncheck +#include +#include +#include +#include CHIP_ERROR CommissionerPairOnNetwork(uint32_t pincode, uint16_t disc, PeerAddress address); CHIP_ERROR CommissionerPairUDC(uint32_t pincode, size_t index); @@ -39,9 +34,9 @@ CHIP_ERROR CommissionerPairUDC(uint32_t pincode, size_t index); CHIP_ERROR InitCommissioner(uint16_t commissionerPort, uint16_t udcListenPort, chip::FabricId fabricId = chip::kUndefinedFabricId); void ShutdownCommissioner(); -DeviceCommissioner * GetDeviceCommissioner(); +chip::Controller::DeviceCommissioner * GetDeviceCommissioner(); CommissionerDiscoveryController * GetCommissionerDiscoveryController(); -SessionKeystore * GetSessionKeystore(); -PersistentStorageDelegate * GetPersistentStorageDelegate(); +chip::Crypto::SessionKeystore * GetSessionKeystore(); +chip::PersistentStorageDelegate * GetPersistentStorageDelegate(); #endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index 105d09f7ad6fc8..18856d40a12f1f 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -305,10 +305,9 @@ chip_test_suite("tests") { test_sources += [ "TestClusterStateCache.cpp" ] } - # On NRF, Open IoT SDK and fake platforms we do not have a realtime clock available, so - # TestEventLogging.cpp would be testing the same thing as - # TestEventLoggingNoUTCTime, but it's not set up to deal with the timestamps - # being that low. + # On NRF, Open IoT SDK and fake platforms we do not have a realtime clock available, + # so TestEventLogging.cpp would be testing the same thing as TestEventLoggingNoUTCTime, + # but it's not set up to deal with the timestamps being that low. if (chip_device_platform != "nrfconnect" && chip_device_platform != "openiotsdk" && chip_device_platform != "fake") { test_sources += [ "TestEventLogging.cpp" ] From 63182c41e71bbbe29ca4ce8fc11c5723f52245aa Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Wed, 27 Nov 2024 12:32:02 +0530 Subject: [PATCH 05/26] dac_revocation: Perform cross validation against crl signer or crl signer delegator (#35144) * dac_revocation: Support crl signer and crl signer delegator - Add crl signer and crl signer delegator cert in the python script which generates the revocation set - perform the cross validation of DAC/PAI with crl signer and crl signer delegator cert - Extended and added unit tests for crl signer delegator case * include algoright and remove the local var declaration * use unused attribute * Fix the buffer overrun and use maybe_unused instead of unused attribute * we do not need to differentiate pai/dac when cross verifying * add checks on return value and unit tests on malformed crl signer cert * use std::string instead of const char * * address some more reviews * Update src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp Co-authored-by: Boris Zbarsky --------- Co-authored-by: Boris Zbarsky --- .../TestDACRevocationDelegateImpl.cpp | 175 ++++++++++++++++-- .../TestDACRevocationDelegateImpl.h | 13 ++ .../TestDeviceAttestationCredentials.cpp | 66 ++++++- 3 files changed, 231 insertions(+), 23 deletions(-) diff --git a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp index 0db03372195184..0ad7de13e80f5c 100644 --- a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp +++ b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -30,6 +31,9 @@ namespace chip { namespace Credentials { namespace { + +static constexpr uint32_t kMaxIssuerBase64Len = BASE64_ENCODED_LEN(kMaxCertificateDistinguishedNameLength); + CHIP_ERROR BytesToHexStr(const ByteSpan & bytes, MutableCharSpan & outHexStr) { Encoding::HexFlags flags = Encoding::HexFlags::kUppercase; @@ -37,6 +41,42 @@ CHIP_ERROR BytesToHexStr(const ByteSpan & bytes, MutableCharSpan & outHexStr) outHexStr.reduce_size(2 * bytes.size()); return CHIP_NO_ERROR; } + +CHIP_ERROR X509_PemToDer(const std::string & pemCert, MutableByteSpan & derCert) +{ + std::string beginMarker = "-----BEGIN CERTIFICATE-----"; + std::string endMarker = "-----END CERTIFICATE-----"; + + std::size_t beginPos = pemCert.find(beginMarker); + VerifyOrReturnError(beginPos != std::string::npos, CHIP_ERROR_INVALID_ARGUMENT); + + std::size_t endPos = pemCert.find(endMarker); + VerifyOrReturnError(endPos != std::string::npos, CHIP_ERROR_INVALID_ARGUMENT); + + VerifyOrReturnError(beginPos < endPos, CHIP_ERROR_INVALID_ARGUMENT); + + // Extract content between markers + std::string plainB64Str = pemCert.substr(beginPos + beginMarker.length(), endPos - (beginPos + beginMarker.length())); + + // Remove all newline characters '\n' and '\r' + plainB64Str.erase(std::remove(plainB64Str.begin(), plainB64Str.end(), '\n'), plainB64Str.end()); + plainB64Str.erase(std::remove(plainB64Str.begin(), plainB64Str.end(), '\r'), plainB64Str.end()); + + VerifyOrReturnError(!plainB64Str.empty(), CHIP_ERROR_INVALID_ARGUMENT); + + // Verify we have enough room to store the decoded certificate + size_t maxDecodeLen = BASE64_MAX_DECODED_LEN(plainB64Str.size()); + VerifyOrReturnError(derCert.size() >= maxDecodeLen, CHIP_ERROR_BUFFER_TOO_SMALL); + + // decode b64 + uint16_t derLen = Base64Decode(plainB64Str.c_str(), static_cast(plainB64Str.size()), derCert.data()); + VerifyOrReturnError(derLen != UINT16_MAX, CHIP_ERROR_INVALID_ARGUMENT); + + derCert.reduce_size(derLen); + + return CHIP_NO_ERROR; +} + } // anonymous namespace CHIP_ERROR TestDACRevocationDelegateImpl::SetDeviceAttestationRevocationSetPath(std::string_view path) @@ -52,6 +92,58 @@ void TestDACRevocationDelegateImpl::ClearDeviceAttestationRevocationSetPath() mDeviceAttestationRevocationSetPath = mDeviceAttestationRevocationSetPath.substr(0, 0); } +// outSubject is subject encoded as base64 string +// outKeyId is SKID encoded as hex string +CHIP_ERROR TestDACRevocationDelegateImpl::GetSubjectAndKeyIdFromPEMCert(const std::string & certPEM, std::string & outSubject, + std::string & outKeyId) +{ + // buffers and spans for storing crl signer delegator OR crl signer cert info + char subjectBuf[kMaxIssuerBase64Len] = { 0 }; + char skidBuf[2 * kAuthorityKeyIdentifierLength] = { 0 }; + uint8_t certDerBuf[kMax_x509_Certificate_Length] = { 0 }; + + MutableCharSpan subject(subjectBuf); + MutableCharSpan keyId(skidBuf); + MutableByteSpan certDER(certDerBuf); + + ReturnLogErrorOnFailure(X509_PemToDer(certPEM, certDER)); + ReturnErrorOnFailure(GetSubjectNameBase64Str(certDER, subject)); + ReturnErrorOnFailure(GetSKIDHexStr(certDER, keyId)); + + outSubject = std::string(subject.data(), subject.size()); + outKeyId = std::string(keyId.data(), keyId.size()); + + return CHIP_NO_ERROR; +} + +// Check if issuer and AKID matches with the crl signer OR crl signer delegator's subject and SKID +bool TestDACRevocationDelegateImpl::CrossValidateCert(const Json::Value & revokedSet, const std::string & akidHexStr, + const std::string & issuerNameBase64Str) +{ + std::string certPEM; + [[maybe_unused]] std::string certType; + + if (revokedSet.isMember("crl_signer_delegator")) + { + certPEM = revokedSet["crl_signer_delegator"].asString(); + certType = "CRL Signer delegator"; + } + else + { + certPEM = revokedSet["crl_signer_cert"].asString(); + certType = "CRL Signer"; + } + + std::string subject; // crl signer or crl signer delegator subject + std::string keyId; // crl signer or crl signer delegator SKID + VerifyOrReturnValue(CHIP_NO_ERROR == GetSubjectAndKeyIdFromPEMCert(certPEM, subject, keyId), false); + + ChipLogDetail(NotSpecified, "%s: Subject: %s", certType.c_str(), subject.c_str()); + ChipLogDetail(NotSpecified, "%s: SKID: %s", certType.c_str(), keyId.c_str()); + + return (akidHexStr == keyId && issuerNameBase64Str == subject); +} + // This method parses the below JSON Scheme // [ // { @@ -62,6 +154,8 @@ void TestDACRevocationDelegateImpl::ClearDeviceAttestationRevocationSetPath() // "serial1 bytes as base64", // "serial2 bytes as base64" // ] +// "crl_signer_cert": "", +// "crl_signer_delegator": , // } // ] // @@ -95,6 +189,7 @@ bool TestDACRevocationDelegateImpl::IsEntryInRevocationSet(const CharSpan & akid std::string serialNumber = std::string(serialNumberHexStr.data(), serialNumberHexStr.size()); std::string akid = std::string(akidHexStr.data(), akidHexStr.size()); + // 6.2.4.2. Determining Revocation Status of an Entity for (const auto & revokedSet : jsonData) { if (revokedSet["issuer_name"].asString() != issuerName) @@ -105,6 +200,12 @@ bool TestDACRevocationDelegateImpl::IsEntryInRevocationSet(const CharSpan & akid { continue; } + + // 4.a cross validate PAI with crl signer OR crl signer delegator + // 4.b cross validate DAC with crl signer OR crl signer delegator + VerifyOrReturnValue(CrossValidateCert(revokedSet, akid, issuerName), false); + + // 4.c check if serial number is revoked for (const auto & revokedSerialNumber : revokedSet["revoked_serial_numbers"]) { if (revokedSerialNumber.asString() == serialNumber) @@ -116,14 +217,33 @@ bool TestDACRevocationDelegateImpl::IsEntryInRevocationSet(const CharSpan & akid return false; } -CHIP_ERROR TestDACRevocationDelegateImpl::GetAKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outAKIDHexStr) +CHIP_ERROR TestDACRevocationDelegateImpl::GetKeyIDHexStr(const ByteSpan & certDer, MutableCharSpan & outKeyIDHexStr, bool isAKID) { - uint8_t akidBuf[kAuthorityKeyIdentifierLength]; - MutableByteSpan akid(akidBuf); + static_assert(kAuthorityKeyIdentifierLength == kSubjectKeyIdentifierLength, "AKID and SKID length mismatch"); + + uint8_t keyIdBuf[kAuthorityKeyIdentifierLength]; + MutableByteSpan keyId(keyIdBuf); - ReturnErrorOnFailure(ExtractAKIDFromX509Cert(certDer, akid)); + if (isAKID) + { + ReturnErrorOnFailure(ExtractAKIDFromX509Cert(certDer, keyId)); + } + else + { + ReturnErrorOnFailure(ExtractSKIDFromX509Cert(certDer, keyId)); + } - return BytesToHexStr(akid, outAKIDHexStr); + return BytesToHexStr(keyId, outKeyIDHexStr); +} + +CHIP_ERROR TestDACRevocationDelegateImpl::GetAKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outAKIDHexStr) +{ + return GetKeyIDHexStr(certDer, outAKIDHexStr, true); +} + +CHIP_ERROR TestDACRevocationDelegateImpl::GetSKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outSKIDHexStr) +{ + return GetKeyIDHexStr(certDer, outSKIDHexStr, false /* isAKID */); } CHIP_ERROR TestDACRevocationDelegateImpl::GetSerialNumberHexStr(const ByteSpan & certDer, MutableCharSpan & outSerialNumberHexStr) @@ -135,25 +255,44 @@ CHIP_ERROR TestDACRevocationDelegateImpl::GetSerialNumberHexStr(const ByteSpan & return BytesToHexStr(serialNumber, outSerialNumberHexStr); } -CHIP_ERROR TestDACRevocationDelegateImpl::GetIssuerNameBase64Str(const ByteSpan & certDer, - MutableCharSpan & outIssuerNameBase64String) +CHIP_ERROR TestDACRevocationDelegateImpl::GetRDNBase64Str(const ByteSpan & certDer, MutableCharSpan & outRDNBase64String, + bool isIssuer) { - uint8_t issuerBuf[kMaxCertificateDistinguishedNameLength] = { 0 }; - MutableByteSpan issuer(issuerBuf); + uint8_t rdnBuf[kMaxCertificateDistinguishedNameLength] = { 0 }; + MutableByteSpan rdn(rdnBuf); - ReturnErrorOnFailure(ExtractIssuerFromX509Cert(certDer, issuer)); - VerifyOrReturnError(outIssuerNameBase64String.size() >= BASE64_ENCODED_LEN(issuer.size()), CHIP_ERROR_BUFFER_TOO_SMALL); + if (isIssuer) + { + ReturnErrorOnFailure(ExtractIssuerFromX509Cert(certDer, rdn)); + } + else + { + ReturnErrorOnFailure(ExtractSubjectFromX509Cert(certDer, rdn)); + } - uint16_t encodedLen = Base64Encode(issuer.data(), static_cast(issuer.size()), outIssuerNameBase64String.data()); - outIssuerNameBase64String.reduce_size(encodedLen); + VerifyOrReturnError(outRDNBase64String.size() >= BASE64_ENCODED_LEN(rdn.size()), CHIP_ERROR_BUFFER_TOO_SMALL); + + uint16_t encodedLen = Base64Encode(rdn.data(), static_cast(rdn.size()), outRDNBase64String.data()); + outRDNBase64String.reduce_size(encodedLen); return CHIP_NO_ERROR; } -bool TestDACRevocationDelegateImpl::IsCertificateRevoked(const ByteSpan & certDer) +CHIP_ERROR TestDACRevocationDelegateImpl::GetIssuerNameBase64Str(const ByteSpan & certDer, + MutableCharSpan & outIssuerNameBase64String) { - static constexpr uint32_t maxIssuerBase64Len = BASE64_ENCODED_LEN(kMaxCertificateDistinguishedNameLength); + return GetRDNBase64Str(certDer, outIssuerNameBase64String, true /* isIssuer */); +} + +CHIP_ERROR TestDACRevocationDelegateImpl::GetSubjectNameBase64Str(const ByteSpan & certDer, + MutableCharSpan & outSubjectNameBase64String) +{ + return GetRDNBase64Str(certDer, outSubjectNameBase64String, false /* isIssuer */); +} - char issuerNameBuffer[maxIssuerBase64Len] = { 0 }; +// @param certDer Certificate, in DER format, to check for revocation +bool TestDACRevocationDelegateImpl::IsCertificateRevoked(const ByteSpan & certDer) +{ + char issuerNameBuffer[kMaxIssuerBase64Len] = { 0 }; char serialNumberHexStrBuffer[2 * kMaxCertificateSerialNumberLength] = { 0 }; char akidHexStrBuffer[2 * kAuthorityKeyIdentifierLength] = { 0 }; @@ -170,8 +309,6 @@ bool TestDACRevocationDelegateImpl::IsCertificateRevoked(const ByteSpan & certDe VerifyOrReturnValue(CHIP_NO_ERROR == GetAKIDHexStr(certDer, akid), false); ChipLogDetail(NotSpecified, "AKID: %.*s", static_cast(akid.size()), akid.data()); - // TODO: Cross-validate the CRLSignerCertificate and CRLSignerDelegator per spec: #34587 - return IsEntryInRevocationSet(akid, issuerName, serialNumber); } @@ -183,8 +320,8 @@ void TestDACRevocationDelegateImpl::CheckForRevokedDACChain( if (mDeviceAttestationRevocationSetPath.empty()) { - onCompletion->mCall(onCompletion->mContext, info, attestationError); + return; } ChipLogDetail(NotSpecified, "Checking for revoked DAC in %s", mDeviceAttestationRevocationSetPath.c_str()); diff --git a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h index 2dc169c2b67837..ac1208dbca8e69 100644 --- a/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h +++ b/src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.h @@ -18,6 +18,7 @@ #pragma once #include +#include #include #include @@ -52,11 +53,23 @@ class TestDACRevocationDelegateImpl : public DeviceAttestationRevocationDelegate void ClearDeviceAttestationRevocationSetPath(); private: + bool CrossValidateCert(const Json::Value & revokedSet, const std::string & akIdHexStr, const std::string & issuerNameBase64Str); + + CHIP_ERROR GetKeyIDHexStr(const ByteSpan & certDer, MutableCharSpan & outKeyIDHexStr, bool isAKID); CHIP_ERROR GetAKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outAKIDHexStr); + CHIP_ERROR GetSKIDHexStr(const ByteSpan & certDer, MutableCharSpan & outSKIDHexStr); + CHIP_ERROR GetSerialNumberHexStr(const ByteSpan & certDer, MutableCharSpan & outSerialNumberHexStr); + + CHIP_ERROR GetRDNBase64Str(const ByteSpan & certDer, MutableCharSpan & outRDNBase64String, bool isIssuer); CHIP_ERROR GetIssuerNameBase64Str(const ByteSpan & certDer, MutableCharSpan & outIssuerNameBase64String); + CHIP_ERROR GetSubjectNameBase64Str(const ByteSpan & certDer, MutableCharSpan & outSubjectNameBase64String); + + CHIP_ERROR GetSubjectAndKeyIdFromPEMCert(const std::string & certPEM, std::string & outSubject, std::string & outKeyId); + bool IsEntryInRevocationSet(const CharSpan & akidHexStr, const CharSpan & issuerNameBase64Str, const CharSpan & serialNumberHexStr); + bool IsCertificateRevoked(const ByteSpan & certDer); std::string mDeviceAttestationRevocationSetPath; diff --git a/src/credentials/tests/TestDeviceAttestationCredentials.cpp b/src/credentials/tests/TestDeviceAttestationCredentials.cpp index 0f80df9fa9f6f4..95eb51ce77e08b 100644 --- a/src/credentials/tests/TestDeviceAttestationCredentials.cpp +++ b/src/credentials/tests/TestDeviceAttestationCredentials.cpp @@ -468,12 +468,13 @@ TEST_F(TestDeviceAttestationCredentials, TestDACRevocationDelegateImpl) revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); EXPECT_EQ(attestationResult, AttestationVerificationResult::kSuccess); - // Test DAC is revoked + // Test DAC is revoked, crl signer is PAI itself const char * jsonData = R"( [{ "type": "revocation_set", "issuer_subject_key_id": "AF42B7094DEBD515EC6ECF33B81115225F325288", "issuer_name": "MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw", + "crl_signer_cert": "-----BEGIN CERTIFICATE-----\nMIIB1DCCAXqgAwIBAgIIPmzmUJrYQM0wCgYIKoZIzj0EAwIwMDEYMBYGA1UEAwwP\nTWF0dGVyIFRlc3QgUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTAgFw0yMTA2Mjgx\nNDIzNDNaGA85OTk5MTIzMTIzNTk1OVowRjEYMBYGA1UEAwwPTWF0dGVyIFRlc3Qg\nUEFJMRQwEgYKKwYBBAGConwCAQwERkZGMTEUMBIGCisGAQQBgqJ8AgIMBDgwMDAw\nWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASA3fEbIo8+MfY7z1eY2hRiOuu96C7z\neO6tv7GP4avOMdCO1LIGBLbMxtm1+rZOfeEMt0vgF8nsFRYFbXDyzQsio2YwZDAS\nBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUr0K3\nCU3r1RXsbs8zuBEVIl8yUogwHwYDVR0jBBgwFoAUav0idx9RH+y/FkGXZxDc3DGh\ncX4wCgYIKoZIzj0EAwIDSAAwRQIhAJbJyM8uAYhgBdj1vHLAe3X9mldpWsSRETET\ni+oDPOUDAiAlVJQ75X1T1sR199I+v8/CA2zSm6Y5PsfvrYcUq3GCGQ==\n-----END CERTIFICATE-----", "revoked_serial_numbers": ["0C694F7F866067B2"] }] )"; @@ -481,12 +482,13 @@ TEST_F(TestDeviceAttestationCredentials, TestDACRevocationDelegateImpl) revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); EXPECT_EQ(attestationResult, AttestationVerificationResult::kDacRevoked); - // Test PAI is revoked + // Test PAI is revoked, crl signer is PAA itself jsonData = R"( [{ "type": "revocation_set", "issuer_subject_key_id": "6AFD22771F511FECBF1641976710DCDC31A1717E", "issuer_name": "MDAxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBQTEUMBIGCisGAQQBgqJ8AgEMBEZGRjE=", + "crl_signer_cert": "-----BEGIN CERTIFICATE-----\nMIIBvTCCAWSgAwIBAgIITqjoMYLUHBwwCgYIKoZIzj0EAwIwMDEYMBYGA1UEAwwP\nTWF0dGVyIFRlc3QgUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTAgFw0yMTA2Mjgx\nNDIzNDNaGA85OTk5MTIzMTIzNTk1OVowMDEYMBYGA1UEAwwPTWF0dGVyIFRlc3Qg\nUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTBZMBMGByqGSM49AgEGCCqGSM49AwEH\nA0IABLbLY3KIfyko9brIGqnZOuJDHK2p154kL2UXfvnO2TKijs0Duq9qj8oYShpQ\nNUKWDUU/MD8fGUIddR6Pjxqam3WjZjBkMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD\nVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRq/SJ3H1Ef7L8WQZdnENzcMaFxfjAfBgNV\nHSMEGDAWgBRq/SJ3H1Ef7L8WQZdnENzcMaFxfjAKBggqhkjOPQQDAgNHADBEAiBQ\nqoAC9NkyqaAFOPZTaK0P/8jvu8m+t9pWmDXPmqdRDgIgI7rI/g8j51RFtlM5CBpH\nmUkpxyqvChVI1A0DTVFLJd4=\n-----END CERTIFICATE-----", "revoked_serial_numbers": ["3E6CE6509AD840CD"] }] )"; @@ -494,18 +496,20 @@ TEST_F(TestDeviceAttestationCredentials, TestDACRevocationDelegateImpl) revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); EXPECT_EQ(attestationResult, AttestationVerificationResult::kPaiRevoked); - // Test DAC and PAI both revoked + // Test DAC and PAI both revoked, crl signers are PAI and PAA respectively jsonData = R"( [{ "type": "revocation_set", "issuer_subject_key_id": "AF42B7094DEBD515EC6ECF33B81115225F325288", "issuer_name": "MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw", + "crl_signer_cert": "-----BEGIN CERTIFICATE-----\nMIIB1DCCAXqgAwIBAgIIPmzmUJrYQM0wCgYIKoZIzj0EAwIwMDEYMBYGA1UEAwwP\nTWF0dGVyIFRlc3QgUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTAgFw0yMTA2Mjgx\nNDIzNDNaGA85OTk5MTIzMTIzNTk1OVowRjEYMBYGA1UEAwwPTWF0dGVyIFRlc3Qg\nUEFJMRQwEgYKKwYBBAGConwCAQwERkZGMTEUMBIGCisGAQQBgqJ8AgIMBDgwMDAw\nWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASA3fEbIo8+MfY7z1eY2hRiOuu96C7z\neO6tv7GP4avOMdCO1LIGBLbMxtm1+rZOfeEMt0vgF8nsFRYFbXDyzQsio2YwZDAS\nBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUr0K3\nCU3r1RXsbs8zuBEVIl8yUogwHwYDVR0jBBgwFoAUav0idx9RH+y/FkGXZxDc3DGh\ncX4wCgYIKoZIzj0EAwIDSAAwRQIhAJbJyM8uAYhgBdj1vHLAe3X9mldpWsSRETET\ni+oDPOUDAiAlVJQ75X1T1sR199I+v8/CA2zSm6Y5PsfvrYcUq3GCGQ==\n-----END CERTIFICATE-----", "revoked_serial_numbers": ["0C694F7F866067B2"] }, { "type": "revocation_set", "issuer_subject_key_id": "6AFD22771F511FECBF1641976710DCDC31A1717E", "issuer_name": "MDAxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBQTEUMBIGCisGAQQBgqJ8AgEMBEZGRjE=", + "crl_signer_cert": "-----BEGIN CERTIFICATE-----\nMIIBvTCCAWSgAwIBAgIITqjoMYLUHBwwCgYIKoZIzj0EAwIwMDEYMBYGA1UEAwwP\nTWF0dGVyIFRlc3QgUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTAgFw0yMTA2Mjgx\nNDIzNDNaGA85OTk5MTIzMTIzNTk1OVowMDEYMBYGA1UEAwwPTWF0dGVyIFRlc3Qg\nUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTBZMBMGByqGSM49AgEGCCqGSM49AwEH\nA0IABLbLY3KIfyko9brIGqnZOuJDHK2p154kL2UXfvnO2TKijs0Duq9qj8oYShpQ\nNUKWDUU/MD8fGUIddR6Pjxqam3WjZjBkMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD\nVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRq/SJ3H1Ef7L8WQZdnENzcMaFxfjAfBgNV\nHSMEGDAWgBRq/SJ3H1Ef7L8WQZdnENzcMaFxfjAKBggqhkjOPQQDAgNHADBEAiBQ\nqoAC9NkyqaAFOPZTaK0P/8jvu8m+t9pWmDXPmqdRDgIgI7rI/g8j51RFtlM5CBpH\nmUkpxyqvChVI1A0DTVFLJd4=\n-----END CERTIFICATE-----", "revoked_serial_numbers": ["3E6CE6509AD840CD"] }] )"; @@ -522,11 +526,13 @@ TEST_F(TestDeviceAttestationCredentials, TestDACRevocationDelegateImpl) EXPECT_EQ(attestationResult, AttestationVerificationResult::kSuccess); // Test issuer does not match + // crl_signer_cert is not valid and just used for testing jsonData = R"( [{ "type": "revocation_set", "issuer_subject_key_id": "BF42B7094DEBD515EC6ECF33B81115225F325289", "issuer_name": "MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw", + "crl_signer_cert": "-----BEGIN CERTIFICATE-----\nMIIBvTCCAWSgAwIBAgIITqjoMYLUHBwwCgYIKoZIzj0EAwIwMDEYMBYGA1UEAwwP\nTWF0dGVyIFRlc3QgUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTAgFw0yMTA2Mjgx\nNDIzNDNaGA85OTk5MTIzMTIzNTk1OVowMDEYMBYGA1UEAwwPTWF0dGVyIFRlc3Qg\nUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTBZMBMGByqGSM49AgEGCCqGSM49AwEH\nA0IABLbLY3KIfyko9brIGqnZOuJDHK2p154kL2UXfvnO2TKijs0Duq9qj8oYShpQ\nNUKWDUU/MD8fGUIddR6Pjxqam3WjZjBkMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD\nVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRq/SJ3H1Ef7L8WQZdnENzcMaFxfjAfBgNV\nHSMEGDAWgBRq/SJ3H1Ef7L8WQZdnENzcMaFxfjAKBggqhkjOPQQDAgNHADBEAiBQ\nqoAC9NkyqaAFOPZTaK0P/8jvu8m+t9pWmDXPmqdRDgIgI7rI/g8j51RFtlM5CBpH\nmUkpxyqvChVI1A0DTVFLJd4=\n-----END CERTIFICATE-----", "revoked_serial_numbers": ["0C694F7F866067B2"] }] )"; @@ -535,11 +541,13 @@ TEST_F(TestDeviceAttestationCredentials, TestDACRevocationDelegateImpl) EXPECT_EQ(attestationResult, AttestationVerificationResult::kSuccess); // Test subject key ID does not match + // crl_signer_cert is not valid and just used for testing jsonData = R"( [{ "type": "revocation_set", "issuer_subject_key_id": "BF42B7094DEBD515EC6ECF33B81115225F325289", "issuer_name": "MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw", + "crl_signer_cert": "-----BEGIN CERTIFICATE-----\nMIIBvTCCAWSgAwIBAgIITqjoMYLUHBwwCgYIKoZIzj0EAwIwMDEYMBYGA1UEAwwP\nTWF0dGVyIFRlc3QgUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTAgFw0yMTA2Mjgx\nNDIzNDNaGA85OTk5MTIzMTIzNTk1OVowMDEYMBYGA1UEAwwPTWF0dGVyIFRlc3Qg\nUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTBZMBMGByqGSM49AgEGCCqGSM49AwEH\nA0IABLbLY3KIfyko9brIGqnZOuJDHK2p154kL2UXfvnO2TKijs0Duq9qj8oYShpQ\nNUKWDUU/MD8fGUIddR6Pjxqam3WjZjBkMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD\nVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRq/SJ3H1Ef7L8WQZdnENzcMaFxfjAfBgNV\nHSMEGDAWgBRq/SJ3H1Ef7L8WQZdnENzcMaFxfjAKBggqhkjOPQQDAgNHADBEAiBQ\nqoAC9NkyqaAFOPZTaK0P/8jvu8m+t9pWmDXPmqdRDgIgI7rI/g8j51RFtlM5CBpH\nmUkpxyqvChVI1A0DTVFLJd4=\n-----END CERTIFICATE-----", "revoked_serial_numbers": ["0C694F7F866067B2"] }] )"; @@ -548,11 +556,13 @@ TEST_F(TestDeviceAttestationCredentials, TestDACRevocationDelegateImpl) EXPECT_EQ(attestationResult, AttestationVerificationResult::kSuccess); // Test serial number does not match + // crl_signer_cert is not valid and just used for testing jsonData = R"( [{ "type": "revocation_set", "issuer_subject_key_id": "AF42B7094DEBD515EC6ECF33B81115225F325288", "issuer_name": "MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw", + "crl_signer_cert": "-----BEGIN CERTIFICATE-----\nMIIB1DCCAXqgAwIBAgIIPmzmUJrYQM0wCgYIKoZIzj0EAwIwMDEYMBYGA1UEAwwP\nTWF0dGVyIFRlc3QgUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTAgFw0yMTA2Mjgx\nNDIzNDNaGA85OTk5MTIzMTIzNTk1OVowRjEYMBYGA1UEAwwPTWF0dGVyIFRlc3Qg\nUEFJMRQwEgYKKwYBBAGConwCAQwERkZGMTEUMBIGCisGAQQBgqJ8AgIMBDgwMDAw\nWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASA3fEbIo8+MfY7z1eY2hRiOuu96C7z\neO6tv7GP4avOMdCO1LIGBLbMxtm1+rZOfeEMt0vgF8nsFRYFbXDyzQsio2YwZDAS\nBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUr0K3\nCU3r1RXsbs8zuBEVIl8yUogwHwYDVR0jBBgwFoAUav0idx9RH+y/FkGXZxDc3DGh\ncX4wCgYIKoZIzj0EAwIDSAAwRQIhAJbJyM8uAYhgBdj1vHLAe3X9mldpWsSRETET\ni+oDPOUDAiAlVJQ75X1T1sR199I+v8/CA2zSm6Y5PsfvrYcUq3GCGQ==\n-----END CERTIFICATE-----", "revoked_serial_numbers": ["3E6CE6509AD840CD1", "BC694F7F866067B1"] }] )"; @@ -560,16 +570,64 @@ TEST_F(TestDeviceAttestationCredentials, TestDACRevocationDelegateImpl) revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); EXPECT_EQ(attestationResult, AttestationVerificationResult::kSuccess); - // Test starting serial number bytes match but not all + // Test starting serial number bytes match but not all, + // crl_signer_cert is not valid and just used for testing jsonData = R"( [{ "type": "revocation_set", "issuer_subject_key_id": "AF42B7094DEBD515EC6ECF33B81115225F325288", "issuer_name": "MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw", + "crl_signer_cert": "-----BEGIN CERTIFICATE-----\nMIIB1DCCAXqgAwIBAgIIPmzmUJrYQM0wCgYIKoZIzj0EAwIwMDEYMBYGA1UEAwwP\nTWF0dGVyIFRlc3QgUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTAgFw0yMTA2Mjgx\nNDIzNDNaGA85OTk5MTIzMTIzNTk1OVowRjEYMBYGA1UEAwwPTWF0dGVyIFRlc3Qg\nUEFJMRQwEgYKKwYBBAGConwCAQwERkZGMTEUMBIGCisGAQQBgqJ8AgIMBDgwMDAw\nWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASA3fEbIo8+MfY7z1eY2hRiOuu96C7z\neO6tv7GP4avOMdCO1LIGBLbMxtm1+rZOfeEMt0vgF8nsFRYFbXDyzQsio2YwZDAS\nBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUr0K3\nCU3r1RXsbs8zuBEVIl8yUogwHwYDVR0jBBgwFoAUav0idx9RH+y/FkGXZxDc3DGh\ncX4wCgYIKoZIzj0EAwIDSAAwRQIhAJbJyM8uAYhgBdj1vHLAe3X9mldpWsSRETET\ni+oDPOUDAiAlVJQ75X1T1sR199I+v8/CA2zSm6Y5PsfvrYcUq3GCGQ==\n-----END CERTIFICATE-----", "revoked_serial_numbers": ["0C694F7F866067B21234"] }] )"; WriteTestRevokedData(jsonData, tmpJsonFile); revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); EXPECT_EQ(attestationResult, AttestationVerificationResult::kSuccess); + + // Test DAC is revoked, and crl signer delegator is present + // crl_signer_cert is not valid and just used for testing + jsonData = R"( + [{ + "type": "revocation_set", + "issuer_subject_key_id": "AF42B7094DEBD515EC6ECF33B81115225F325288", + "issuer_name": "MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw", + "crl_signer_cert": "-----BEGIN CERTIFICATE-----\nMIIB1DCCAXqgAwIBAgIIPmzmUJrYQM0wCgYIKoZIzj0EAwIwMDEYMBYGA1UEAwwP\nTWF0dGVyIFRlc3QgUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTAgFw0yMTA2Mjgx\nNDIzNDNaGA85OTk5MTIzMTIzNTk1OVowRjEYMBYGA1UEAwwPTWF0dGVyIFRlc3Qg\nUEFJMRQwEgYKKwYBBAGConwCAQwERkZGMTEUMBIGCisGAQQBgqJ8AgIMBDgwMDAw\nWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASA3fEbIo8+MfY7z1eY2hRiOuu96C7z\neO6tv7GP4avOMdCO1LIGBLbMxtm1+rZOfeEMt0vgF8nsFRYFbXDyzQsio2YwZDAS\nBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUr0K3\nCU3r1RXsbs8zuBEVIl8yUogwHwYDVR0jBBgwFoAUav0idx9RH+y/FkGXZxDc3DGh\ncX4wCgYIKoZIzj0EAwIDSAAwRQIhAJbJyM8uAYhgBdj1vHLAe3X9mldpWsSRETET\ni+oDPOUDAiAlVJQ75X1T1sR199I+v8/CA2zSm6Y5PsfvrYcUq3GCGQ==\n-----END CERTIFICATE-----", + "crl_signer_delegator": "-----BEGIN CERTIFICATE-----\nMIIB1DCCAXqgAwIBAgIIPmzmUJrYQM0wCgYIKoZIzj0EAwIwMDEYMBYGA1UEAwwP\nTWF0dGVyIFRlc3QgUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTAgFw0yMTA2Mjgx\nNDIzNDNaGA85OTk5MTIzMTIzNTk1OVowRjEYMBYGA1UEAwwPTWF0dGVyIFRlc3Qg\nUEFJMRQwEgYKKwYBBAGConwCAQwERkZGMTEUMBIGCisGAQQBgqJ8AgIMBDgwMDAw\nWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASA3fEbIo8+MfY7z1eY2hRiOuu96C7z\neO6tv7GP4avOMdCO1LIGBLbMxtm1+rZOfeEMt0vgF8nsFRYFbXDyzQsio2YwZDAS\nBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUr0K3\nCU3r1RXsbs8zuBEVIl8yUogwHwYDVR0jBBgwFoAUav0idx9RH+y/FkGXZxDc3DGh\ncX4wCgYIKoZIzj0EAwIDSAAwRQIhAJbJyM8uAYhgBdj1vHLAe3X9mldpWsSRETET\ni+oDPOUDAiAlVJQ75X1T1sR199I+v8/CA2zSm6Y5PsfvrYcUq3GCGQ==\n-----END CERTIFICATE-----", + "revoked_serial_numbers": ["0C694F7F866067B2"] + }] + )"; + WriteTestRevokedData(jsonData, tmpJsonFile); + revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); + EXPECT_EQ(attestationResult, AttestationVerificationResult::kDacRevoked); + + // Test with invalid crl signer cert missing begin and end cert markers + jsonData = R"( + [{ + "type": "revocation_set", + "issuer_subject_key_id": "AF42B7094DEBD515EC6ECF33B81115225F325288", + "issuer_name": "MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw", + "crl_signer_cert": "MIIB1DCCAXqgAwIBAgIIPmzmUJrYQM0wCgYIKoZIzj0EAwIwMDEYMBYGA1UEAwwP\nTWF0dGVyIFRlc3QgUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTAgFw0yMTA2Mjgx\nNDIzNDNaGA85OTk5MTIzMTIzNTk1OVowRjEYMBYGA1UEAwwPTWF0dGVyIFRlc3Qg\nUEFJMRQwEgYKKwYBBAGConwCAQwERkZGMTEUMBIGCisGAQQBgqJ8AgIMBDgwMDAw\nWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASA3fEbIo8+MfY7z1eY2hRiOuu96C7z\neO6tv7GP4avOMdCO1LIGBLbMxtm1+rZOfeEMt0vgF8nsFRYFbXDyzQsio2YwZDAS\nBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUr0K3\nCU3r1RXsbs8zuBEVIl8yUogwHwYDVR0jBBgwFoAUav0idx9RH+y/FkGXZxDc3DGh\ncX4wCgYIKoZIzj0EAwIDSAAwRQIhAJbJyM8uAYhgBdj1vHLAe3X9mldpWsSRETET\ni+oDPOUDAiAlVJQ75X1T1sR199I+v8/CA2zSm6Y5PsfvrYcUq3GCGQ==" + "revoked_serial_numbers": ["0C694F7F866067B2"] + }] + )"; + + WriteTestRevokedData(jsonData, tmpJsonFile); + revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); + EXPECT_EQ(attestationResult, AttestationVerificationResult::kSuccess); + + // test with malformed crl signer certificate + jsonData = R"( + [{ + "type": "revocation_set", + "issuer_subject_key_id": "AF42B7094DEBD515EC6ECF33B81115225F325288", + "issuer_name": "MEYxGDAWBgNVBAMMD01hdHRlciBUZXN0IFBBSTEUMBIGCisGAQQBgqJ8AgEMBEZGRjExFDASBgorBgEEAYKifAICDAQ4MDAw", + "crl_signer_cert": "-----BEGIN CERTIFICATE-----\nMIIB1DCCAXqgAwIBAgIIPmzmUJrYQM0wCgYIKoZIzj0EAwIwMDEYMBYGA1UEAwwP\nNDIzNDNaGA85OTk5MTIzMTIzNTk1OVowRjEYMBYGA1UEAwwPTWF0dGVyIFRlc3Qg\nUEFJMRQwEgYKKwYBBAGConwCAQwERkZGMTEUMBIGCisGAQQBgqJ8AgIMBDgwMDAw\nWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASA3fEbIo8+MfY7z1eY2hRiOuu96C7z\neO6tv7GP4avOMdCO1LIGBLbMxtm1+rZOfeEMt0vgF8nsFRYFbXDyzQsio2YwZDAS\nBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUr0K3\nCU3r1RXsbs8zuBEVIl8yUogwHwYDVR0jBBgwFoAUav0idx9RH+y/FkGXZxDc3DGh\ncX4wCgYIKoZIzj0EAwIDSAAwRQIhAJbJyM8uAYhgBdj1vHLAe3X9mldpWsSRETET\ni+oDPOUDAiAlVJQ75X1T1sR199I+v8/CA2zSm6Y5PsfvrYcUq3GCGQ==\n-----END CERTIFICATE-----", + "revoked_serial_numbers": ["0C694F7F866067B2"] + }] + )"; + + WriteTestRevokedData(jsonData, tmpJsonFile); + revocationDelegateImpl.CheckForRevokedDACChain(info, &attestationInformationVerificationCallback); + EXPECT_EQ(attestationResult, AttestationVerificationResult::kSuccess); } From 1ad661e349ee74a6d2073a2a4d994bc147ae7467 Mon Sep 17 00:00:00 2001 From: sarthak shaha Date: Wed, 27 Nov 2024 07:38:24 -0500 Subject: [PATCH 06/26] removed unnecessary include (#36646) --- examples/platform/silabs/sensors/AirQuality/AirQualitySensor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/platform/silabs/sensors/AirQuality/AirQualitySensor.cpp b/examples/platform/silabs/sensors/AirQuality/AirQualitySensor.cpp index 43c5a5573bd610..e693a260214851 100644 --- a/examples/platform/silabs/sensors/AirQuality/AirQualitySensor.cpp +++ b/examples/platform/silabs/sensors/AirQuality/AirQualitySensor.cpp @@ -26,7 +26,6 @@ extern "C" { #endif #include -#include } #include "sl_i2cspm_instances.h" #endif // USE_SPARKFUN_AIR_QUALITY_SENSOR From 29165e9ed958adf05395804ef50631365836ced3 Mon Sep 17 00:00:00 2001 From: shgutte <102281713+shgutte@users.noreply.github.com> Date: Wed, 27 Nov 2024 19:27:19 +0530 Subject: [PATCH 07/26] [Silabs] Adds fix for support default value in refrigerator alarm cluster Refrigerator application (#36651) * Adds changes for supported value * Adds changes for the supported value --- .../silabs/data_model/refrigerator-thread-app.matter | 2 +- .../silabs/data_model/refrigerator-thread-app.zap | 2 +- .../silabs/data_model/refrigerator-wifi-app.matter | 2 +- .../silabs/data_model/refrigerator-wifi-app.zap | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/refrigerator-app/silabs/data_model/refrigerator-thread-app.matter b/examples/refrigerator-app/silabs/data_model/refrigerator-thread-app.matter index 4cafac39256b78..813ade53790060 100644 --- a/examples/refrigerator-app/silabs/data_model/refrigerator-thread-app.matter +++ b/examples/refrigerator-app/silabs/data_model/refrigerator-thread-app.matter @@ -1929,7 +1929,7 @@ endpoint 1 { server cluster RefrigeratorAlarm { ram attribute mask default = 1; ram attribute state default = 0; - ram attribute supported default = 0; + ram attribute supported default = 1; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute attributeList; diff --git a/examples/refrigerator-app/silabs/data_model/refrigerator-thread-app.zap b/examples/refrigerator-app/silabs/data_model/refrigerator-thread-app.zap index 31351d35efe49b..d5933140eff7fd 100644 --- a/examples/refrigerator-app/silabs/data_model/refrigerator-thread-app.zap +++ b/examples/refrigerator-app/silabs/data_model/refrigerator-thread-app.zap @@ -3453,7 +3453,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": "1", "reportable": 1, "minInterval": 1, "maxInterval": 65534, diff --git a/examples/refrigerator-app/silabs/data_model/refrigerator-wifi-app.matter b/examples/refrigerator-app/silabs/data_model/refrigerator-wifi-app.matter index 234974cf1d83aa..857c8058f119a5 100644 --- a/examples/refrigerator-app/silabs/data_model/refrigerator-wifi-app.matter +++ b/examples/refrigerator-app/silabs/data_model/refrigerator-wifi-app.matter @@ -1837,7 +1837,7 @@ endpoint 1 { server cluster RefrigeratorAlarm { ram attribute mask default = 1; ram attribute state default = 0; - ram attribute supported default = 0; + ram attribute supported default = 1; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute attributeList; diff --git a/examples/refrigerator-app/silabs/data_model/refrigerator-wifi-app.zap b/examples/refrigerator-app/silabs/data_model/refrigerator-wifi-app.zap index 34ba99ff801652..53f028aef19613 100644 --- a/examples/refrigerator-app/silabs/data_model/refrigerator-wifi-app.zap +++ b/examples/refrigerator-app/silabs/data_model/refrigerator-wifi-app.zap @@ -3358,7 +3358,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": "1", "reportable": 1, "minInterval": 1, "maxInterval": 65534, From e98f2b239aae657a10043bad9aa61f4717d059be Mon Sep 17 00:00:00 2001 From: Ricardo Casallas <77841255+rcasallas-silabs@users.noreply.github.com> Date: Wed, 27 Nov 2024 09:53:03 -0500 Subject: [PATCH 08/26] [Silabs] PSA Crypto PAL customized for EFR32. (#36575) * [Silabs] PSA Crypto PAL customized for EFR32. --- src/crypto/BUILD.gn | 24 +- src/crypto/DefaultSessionKeystore.h | 8 +- src/crypto/crypto.gni | 4 + src/crypto/tests/TestChipCryptoPAL.cpp | 9 +- .../silabs/efr32/CHIPCryptoPALPsaEfr32.cpp | 339 +++++++++++------- src/platform/silabs/efr32/args.gni | 1 + 6 files changed, 247 insertions(+), 138 deletions(-) diff --git a/src/crypto/BUILD.gn b/src/crypto/BUILD.gn index 6f82c93c191fa8..235e8e2f439927 100644 --- a/src/crypto/BUILD.gn +++ b/src/crypto/BUILD.gn @@ -38,6 +38,18 @@ assert( chip_crypto == "platform", "Please select a valid crypto implementation: mbedtls, psa, openssl, boringssl, platform") +if (chip_crypto_keystore == "") { + if (chip_crypto == "psa") { + chip_crypto_keystore = "psa" + } else { + chip_crypto_keystore = "raw" + } +} + +assert(chip_crypto_keystore == "psa" || chip_crypto_keystore == "raw" || + chip_crypto_keystore == "app", + "Please select a valid crypto keystore: psa, raw, app") + buildconfig_header("crypto_buildconfig") { header = "CryptoBuildConfig.h" header_dir = "crypto" @@ -47,11 +59,17 @@ buildconfig_header("crypto_buildconfig") { chip_crypto_openssl = chip_crypto == "openssl" chip_crypto_boringssl = chip_crypto == "boringssl" chip_crypto_platform = chip_crypto == "platform" + chip_crypto_keystore_psa = chip_crypto_keystore == "psa" + chip_crypto_keystore_raw = chip_crypto_keystore == "raw" + chip_crypto_keystore_app = chip_crypto_keystore == "app" defines = [ "CHIP_CRYPTO_MBEDTLS=${chip_crypto_mbedtls}", "CHIP_CRYPTO_PSA=${chip_crypto_psa}", "CHIP_CRYPTO_PSA_SPAKE2P=${chip_crypto_psa_spake2p}", + "CHIP_CRYPTO_KEYSTORE_PSA=${chip_crypto_keystore_psa}", + "CHIP_CRYPTO_KEYSTORE_RAW=${chip_crypto_keystore_raw}", + "CHIP_CRYPTO_KEYSTORE_APP=${chip_crypto_keystore_app}", "CHIP_CRYPTO_OPENSSL=${chip_crypto_openssl}", "CHIP_CRYPTO_BORINGSSL=${chip_crypto_boringssl}", "CHIP_CRYPTO_PLATFORM=${chip_crypto_platform}", @@ -144,18 +162,20 @@ static_library("crypto") { "RandUtils.h", ] - if (chip_crypto == "psa") { + if (chip_crypto_keystore == "psa") { sources += [ "PSAOperationalKeystore.cpp", "PSAOperationalKeystore.h", "PSASessionKeystore.cpp", "PSASessionKeystore.h", ] - } else { + } else if (chip_crypto_keystore == "raw") { sources += [ "RawKeySessionKeystore.cpp", "RawKeySessionKeystore.h", ] + } else { + # Keystore provided by app } if (chip_crypto_psa_spake2p) { diff --git a/src/crypto/DefaultSessionKeystore.h b/src/crypto/DefaultSessionKeystore.h index 8fa6121af5c20d..227455b113f297 100644 --- a/src/crypto/DefaultSessionKeystore.h +++ b/src/crypto/DefaultSessionKeystore.h @@ -21,9 +21,9 @@ #include #endif -#if CHIP_CRYPTO_PSA +#if CHIP_CRYPTO_KEYSTORE_PSA #include -#else +#elif CHIP_CRYPTO_KEYSTORE_RAW #include #endif @@ -34,9 +34,9 @@ namespace Crypto { // when the PSA crypto backend is used, AES encryption/decryption function assume that the input // key handle carries a key reference instead of raw key material, so PSASessionKeystore must be // used instead of RawKeySessionKeystore to initialize the key handle. -#if CHIP_CRYPTO_PSA +#if CHIP_CRYPTO_KEYSTORE_PSA using DefaultSessionKeystore = PSASessionKeystore; -#else +#elif CHIP_CRYPTO_KEYSTORE_RAW using DefaultSessionKeystore = RawKeySessionKeystore; #endif diff --git a/src/crypto/crypto.gni b/src/crypto/crypto.gni index 96f506033bb56e..2630af95b2ca3e 100644 --- a/src/crypto/crypto.gni +++ b/src/crypto/crypto.gni @@ -22,6 +22,10 @@ declare_args() { # Use PSA Spake2+ implementation. Only used if chip_crypto == "psa" chip_crypto_psa_spake2p = false + + # Crypto storage: psa, raw, app. + # app: includes zero new files and disables the unit tests for the keystore. + chip_crypto_keystore = "" } assert( diff --git a/src/crypto/tests/TestChipCryptoPAL.cpp b/src/crypto/tests/TestChipCryptoPAL.cpp index 2d1f5c0612217a..4dd5182e786eb2 100644 --- a/src/crypto/tests/TestChipCryptoPAL.cpp +++ b/src/crypto/tests/TestChipCryptoPAL.cpp @@ -210,6 +210,7 @@ const AesCtrTestEntry theAesCtrTestVector[] = { } }; +#if !(CHIP_CRYPTO_KEYSTORE_APP) struct TestAesKey { public: @@ -245,6 +246,7 @@ struct TestHmacKey DefaultSessionKeystore keystore; Hmac128KeyHandle key; }; +#endif static void TestAES_CTR_128_Encrypt(const AesCtrTestEntry * vector) { @@ -964,6 +966,7 @@ TEST_F(TestChipCryptoPAL, TestHMAC_SHA256_RawKey) EXPECT_EQ(numOfTestsExecuted, numOfTestCases); } +#if !(CHIP_CRYPTO_KEYSTORE_APP) TEST_F(TestChipCryptoPAL, TestHMAC_SHA256_KeyHandle) { HeapChecker heapChecker; @@ -994,6 +997,7 @@ TEST_F(TestChipCryptoPAL, TestHMAC_SHA256_KeyHandle) } EXPECT_EQ(numOfTestsExecuted, numOfTestCases); } +#endif TEST_F(TestChipCryptoPAL, TestHKDF_SHA256) { @@ -1870,7 +1874,6 @@ TEST_F(TestChipCryptoPAL, TestSPAKE2P_RFC) size_t Pverifier_len = sizeof(Pverifier); uint8_t Vverifier[kMAX_Hash_Length]; size_t Vverifier_len = sizeof(Vverifier); - DefaultSessionKeystore keystore; int numOfTestVectors = ArraySize(rfc_tvs); int numOfTestsRan = 0; @@ -1967,7 +1970,9 @@ TEST_F(TestChipCryptoPAL, TestSPAKE2P_RFC) error = Verifier.KeyConfirm(Pverifier, Pverifier_len); EXPECT_EQ(error, CHIP_NO_ERROR); +#if !(CHIP_CRYPTO_KEYSTORE_APP) // Import HKDF key from the test vector to the keystore + DefaultSessionKeystore keystore; HkdfKeyHandle vectorKe; error = keystore.CreateKey(ByteSpan(vector->Ke, vector->Ke_len), vectorKe); EXPECT_EQ(error, CHIP_NO_ERROR); @@ -1988,7 +1993,7 @@ TEST_F(TestChipCryptoPAL, TestSPAKE2P_RFC) keystore.DestroyKey(vectorKe); keystore.DestroyKey(PKe); keystore.DestroyKey(VKe); - +#endif numOfTestsRan += 1; } EXPECT_GT(numOfTestsRan, 0); diff --git a/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp b/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp index a1811a1093337a..fc926ab5a8e5c5 100644 --- a/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp +++ b/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp @@ -26,6 +26,7 @@ #define MBEDTLS_ALLOW_PRIVATE_ACCESS #include +#include #include @@ -98,7 +99,9 @@ using chip::Platform::MemoryFree; #define CHIP_CRYPTO_PAL_PRIVATE_X509(x) x #endif -static void _log_mbedTLS_error(int error_code) +namespace { + +void _log_mbedTLS_error(int error_code) { if (error_code != 0) { @@ -113,7 +116,7 @@ static void _log_mbedTLS_error(int error_code) } } -static void _log_PSA_error(psa_status_t status) +void _log_PSA_error(psa_status_t status) { if (status != 0) { @@ -122,15 +125,6 @@ static void _log_PSA_error(psa_status_t status) } } -static bool _isValidTagLength(size_t tag_length) -{ - if (tag_length == 8 || tag_length == 12 || tag_length == 16) - { - return true; - } - return false; -} - /** * @brief Compare two times * @@ -138,7 +132,7 @@ static bool _isValidTagLength(size_t tag_length) * @param t2 Second time to compare * @return int 0 If both times are idential to the second, -1 if t1 < t2, 1 if t1 > t2. */ -static int timeCompare(mbedtls_x509_time * t1, mbedtls_x509_time * t2) +int TimeCompare(mbedtls_x509_time * t1, mbedtls_x509_time * t2) { VerifyOrReturnValue(t1->year >= t2->year, -1); VerifyOrReturnValue(t1->year <= t2->year, 1); @@ -161,121 +155,117 @@ static int timeCompare(mbedtls_x509_time * t1, mbedtls_x509_time * t2) return 0; } +bool IsBufferNonEmpty(const uint8_t * data, size_t data_length) +{ + return data != nullptr && data_length > 0; +} + +bool IsValidTag(const uint8_t * tag, size_t tag_length) +{ + return tag != nullptr && (tag_length == 8 || tag_length == 12 || tag_length == 16); +} + +} // namespace + CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, const uint8_t * aad, size_t aad_length, const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, uint8_t * tag, size_t tag_length) { - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - size_t output_length = 0; - uint8_t * buffer = nullptr; - bool allocated_buffer = false; + VerifyOrReturnError(IsBufferNonEmpty(nonce, nonce_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsValidTag(tag, tag_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError((ciphertext != nullptr && plaintext != nullptr) || plaintext_length == 0, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(aad != nullptr || aad_length == 0, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(_isValidTagLength(tag_length), error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(CanCastTo(nonce_length), error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + const psa_algorithm_t algorithm = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length); + psa_status_t status = PSA_SUCCESS; + psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT; + size_t out_length; + size_t tag_out_length; - // If the ciphertext and tag outputs aren't a contiguous buffer, the PSA API requires buffer copying - if (Uint8::to_uchar(ciphertext) + plaintext_length != Uint8::to_uchar(tag)) - { - buffer = (uint8_t *) MemoryCalloc(1, plaintext_length + tag_length); - allocated_buffer = true; - VerifyOrExit(buffer != nullptr, error = CHIP_ERROR_NO_MEMORY); - } - - psa_crypto_init(); + status = psa_aead_encrypt_setup(&operation, key.As(), algorithm); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - psa_set_key_type(&attr, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attr, sizeof(Symmetric128BitsKeyByteArray) * 8); - psa_set_key_algorithm(&attr, PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 8)); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_ENCRYPT); + status = psa_aead_set_lengths(&operation, aad_length, plaintext_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - status = psa_driver_wrapper_aead_encrypt(&attr, key.As(), sizeof(Symmetric128BitsKeyByteArray), - PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length), Uint8::to_const_uchar(nonce), - nonce_length, Uint8::to_const_uchar(aad), aad_length, Uint8::to_const_uchar(plaintext), - plaintext_length, allocated_buffer ? buffer : ciphertext, - plaintext_length + tag_length, &output_length); + status = psa_aead_set_nonce(&operation, nonce, nonce_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == plaintext_length + tag_length, error = CHIP_ERROR_INTERNAL); + status = psa_aead_update_ad(&operation, aad, aad_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - if (allocated_buffer) + if (plaintext_length != 0) { - memcpy(Uint8::to_uchar(ciphertext), buffer, plaintext_length); - memcpy(Uint8::to_uchar(tag), buffer + plaintext_length, tag_length); - memset(buffer, 0, plaintext_length + tag_length); - } + status = psa_aead_update(&operation, plaintext, plaintext_length, ciphertext, + PSA_AEAD_UPDATE_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm, plaintext_length), &out_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); -exit: - if (allocated_buffer) + ciphertext += out_length; + + status = psa_aead_finish(&operation, ciphertext, PSA_AEAD_FINISH_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm), &out_length, tag, + tag_length, &tag_out_length); + } + else { - MemoryFree(buffer); + status = psa_aead_finish(&operation, nullptr, 0, &out_length, tag, tag_length, &tag_out_length); } - psa_reset_key_attributes(&attr); - return error; + VerifyOrReturnError(status == PSA_SUCCESS && tag_length == tag_out_length, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; } -CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, const uint8_t * aad, size_t aad_len, +CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_length, const uint8_t * aad, size_t aad_length, const uint8_t * tag, size_t tag_length, const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * plaintext) { - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - size_t output_length = 0; - uint8_t * buffer = nullptr; - bool allocated_buffer = false; + VerifyOrReturnError(IsBufferNonEmpty(nonce, nonce_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsValidTag(tag, tag_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError((ciphertext != nullptr && plaintext != nullptr) || ciphertext_length == 0, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(aad != nullptr || aad_length == 0, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(_isValidTagLength(tag_length), error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); + const psa_algorithm_t algorithm = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length); + psa_status_t status = PSA_SUCCESS; + psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT; + size_t outLength; - // If the ciphertext and tag outputs aren't a contiguous buffer, the PSA API requires buffer copying - if (Uint8::to_const_uchar(ciphertext) + ciphertext_len != Uint8::to_const_uchar(tag)) - { - buffer = (uint8_t *) MemoryCalloc(1, ciphertext_len + tag_length); - allocated_buffer = true; - VerifyOrExit(buffer != nullptr, error = CHIP_ERROR_NO_MEMORY); - } + status = psa_aead_decrypt_setup(&operation, key.As(), algorithm); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - psa_crypto_init(); + status = psa_aead_set_lengths(&operation, aad_length, ciphertext_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - psa_set_key_type(&attr, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attr, sizeof(Symmetric128BitsKeyByteArray) * 8); - psa_set_key_algorithm(&attr, PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 8)); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DECRYPT); + status = psa_aead_set_nonce(&operation, nonce, nonce_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - if (allocated_buffer) + if (aad_length != 0) { - memcpy(buffer, ciphertext, ciphertext_len); - memcpy(buffer + ciphertext_len, tag, tag_length); + status = psa_aead_update_ad(&operation, aad, aad_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); } - - status = - psa_driver_wrapper_aead_decrypt(&attr, key.As(), sizeof(Symmetric128BitsKeyByteArray), - PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length), Uint8::to_const_uchar(nonce), - nonce_length, Uint8::to_const_uchar(aad), aad_len, allocated_buffer ? buffer : ciphertext, - ciphertext_len + tag_length, plaintext, ciphertext_len, &output_length); - - if (allocated_buffer) + else { - memset(buffer, 0, ciphertext_len + tag_length); + ChipLogDetail(Crypto, "AES_CCM_decrypt: Using aad == null path"); } - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == ciphertext_len, error = CHIP_ERROR_INTERNAL); -exit: - if (allocated_buffer) + if (ciphertext_length != 0) + { + status = psa_aead_update(&operation, ciphertext, ciphertext_length, plaintext, + PSA_AEAD_UPDATE_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm, ciphertext_length), &outLength); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + plaintext += outLength; + + status = psa_aead_verify(&operation, plaintext, PSA_AEAD_VERIFY_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm), &outLength, tag, + tag_length); + } + else { - MemoryFree(buffer); + status = psa_aead_verify(&operation, nullptr, 0, &outLength, tag, tag_length); } - psa_reset_key_attributes(&attr); - return error; + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; } CHIP_ERROR Hash_SHA256(const uint8_t * data, const size_t data_length, uint8_t * out_buffer) @@ -832,46 +822,45 @@ bool IsBufferContentEqualConstantTime(const void * a, const void * b, size_t n) CHIP_ERROR P256Keypair::Initialize(ECPKeyTarget key_target) { - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_plaintext_ecp_keypair * keypair = to_keypair(&mKeypair); - size_t output_length; + VerifyOrReturnError(!mInitialized, CHIP_ERROR_INCORRECT_STATE); - if (mInitialized) - { - return CHIP_ERROR_INCORRECT_STATE; - } + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_SUCCESS; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + PsaP256KeypairContext & context = ToPsaContext(mKeypair); + size_t publicKeyLength = 0; - // Step 1: Generate a volatile new key - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - psa_crypto_init(); - - psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); - psa_set_key_bits(&attr, 256); - psa_set_key_algorithm(&attr, PSA_ALG_ECDH); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT); + // Type based on ECC with the elliptic curve SECP256r1 -> PSA_ECC_FAMILY_SECP_R1 + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attributes, kP256_PrivateKey_Length * 8); - status = psa_driver_wrapper_generate_key(&attr, keypair->privkey, sizeof(keypair->privkey), &output_length); + if (key_target == ECPKeyTarget::ECDH) + { + psa_set_key_algorithm(&attributes, PSA_ALG_ECDH); + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); + } + else if (key_target == ECPKeyTarget::ECDSA) + { + psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_MESSAGE); + } + else + { + ExitNow(error = CHIP_ERROR_UNKNOWN_KEY_TYPE); + } + status = psa_generate_key(&attributes, &context.key_id); VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == kP256_PrivateKey_Length, error = CHIP_ERROR_INTERNAL); - - keypair->bitlen = 256; - - // Step 2: Export the public key into the pubkey member - status = psa_driver_wrapper_export_public_key(&attr, keypair->privkey, sizeof(keypair->privkey), Uint8::to_uchar(mPublicKey), - mPublicKey.Length(), &output_length); + status = psa_export_public_key(context.key_id, mPublicKey.Bytes(), mPublicKey.Length(), &publicKeyLength); VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == kP256_PublicKey_Length, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(publicKeyLength == kP256_PublicKey_Length, error = CHIP_ERROR_INTERNAL); + + mInitialized = true; exit: - _log_PSA_error(status); - if (error == CHIP_NO_ERROR) - { - mInitialized = true; - } - psa_reset_key_attributes(&attr); + LogPsaError(status); + psa_reset_key_attributes(&attributes); return error; } @@ -1690,15 +1679,15 @@ CHIP_ERROR ValidateCertificateChain(const uint8_t * rootCertificate, size_t root VerifyOrExit(mbedResult == 0, (result = CertificateChainValidationResult::kRootFormatInvalid, error = CHIP_ERROR_INTERNAL)); /* Validates that intermediate and root certificates are valid at the time of the leaf certificate's start time. */ - compare_from = timeCompare(&leaf_valid_from, &rootCert.valid_from); - compare_until = timeCompare(&leaf_valid_from, &rootCert.valid_to); + compare_from = TimeCompare(&leaf_valid_from, &rootCert.valid_from); + compare_until = TimeCompare(&leaf_valid_from, &rootCert.valid_to); VerifyOrExit((compare_from >= 0) && (compare_until <= 0), (result = CertificateChainValidationResult::kChainInvalid, error = CHIP_ERROR_CERT_NOT_TRUSTED)); cert = certChain.next; while (cert) { - compare_from = timeCompare(&leaf_valid_from, &cert->valid_from); - compare_until = timeCompare(&leaf_valid_from, &cert->valid_to); + compare_from = TimeCompare(&leaf_valid_from, &cert->valid_from); + compare_until = TimeCompare(&leaf_valid_from, &cert->valid_to); VerifyOrExit((compare_from >= 0) && (compare_until <= 0), (result = CertificateChainValidationResult::kChainInvalid, error = CHIP_ERROR_CERT_NOT_TRUSTED)); cert = cert->next; @@ -2419,5 +2408,95 @@ CHIP_ERROR ReplaceCertIfResignedCertFound(const ByteSpan & referenceCertificate, #endif // defined(MBEDTLS_X509_CRT_PARSE_C) } +void LogPsaError(psa_status_t status) +{ + if (status != PSA_SUCCESS) + { + ChipLogError(Crypto, "PSA error: %d", static_cast(status)); + } +} + +CHIP_ERROR PsaKdf::Init(const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info) +{ + psa_status_t status = PSA_SUCCESS; + psa_key_attributes_t attrs = PSA_KEY_ATTRIBUTES_INIT; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_DERIVE); + psa_set_key_algorithm(&attrs, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_DERIVE); + + status = psa_import_key(&attrs, secret.data(), secret.size(), &mSecretKeyId); + LogPsaError(status); + psa_reset_key_attributes(&attrs); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return InitOperation(mSecretKeyId, salt, info); +} + +CHIP_ERROR PsaKdf::Init(const HkdfKeyHandle & hkdfKey, const ByteSpan & salt, const ByteSpan & info) +{ + return InitOperation(hkdfKey.As(), salt, info); +} + +CHIP_ERROR PsaKdf::InitOperation(psa_key_id_t hkdfKey, const ByteSpan & salt, const ByteSpan & info) +{ + psa_status_t status = psa_key_derivation_setup(&mOperation, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + if (salt.size() > 0) + { + status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_SALT, salt.data(), salt.size()); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + } + + status = psa_key_derivation_input_key(&mOperation, PSA_KEY_DERIVATION_INPUT_SECRET, hkdfKey); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_INFO, info.data(), info.size()); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR PsaKdf::DeriveBytes(const MutableByteSpan & output) +{ + psa_status_t status = psa_key_derivation_output_bytes(&mOperation, output.data(), output.size()); + LogPsaError(status); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR PsaKdf::DeriveKey(const psa_key_attributes_t & attributes, psa_key_id_t & keyId) +{ + psa_status_t status = psa_key_derivation_output_key(&attributes, &mOperation, &keyId); + LogPsaError(status); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FindFreeKeySlotInRange(psa_key_id_t & keyId, psa_key_id_t start, uint32_t range) +{ + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t end = start + range; + + VerifyOrReturnError(start >= PSA_KEY_ID_USER_MIN && end - 1 <= PSA_KEY_ID_USER_MAX, CHIP_ERROR_INVALID_ARGUMENT); + + for (keyId = start; keyId < end; keyId++) + { + psa_status_t status = psa_get_key_attributes(keyId, &attributes); + if (status == PSA_ERROR_INVALID_HANDLE) + { + return CHIP_NO_ERROR; + } + else if (status != PSA_SUCCESS) + { + return CHIP_ERROR_INTERNAL; + } + } + return CHIP_ERROR_NOT_FOUND; +} + } // namespace Crypto } // namespace chip diff --git a/src/platform/silabs/efr32/args.gni b/src/platform/silabs/efr32/args.gni index 501661866ad61e..95b7519474c420 100644 --- a/src/platform/silabs/efr32/args.gni +++ b/src/platform/silabs/efr32/args.gni @@ -29,6 +29,7 @@ openthread_external_mbedtls = mbedtls_target # default to platform crypto implementation but allow commandline override if (chip_crypto == "") { chip_crypto = "platform" + chip_crypto_keystore = "psa" } chip_device_platform = "efr32" From cb1f4b0432baf96de7a4cdef4965cd1e08c720c4 Mon Sep 17 00:00:00 2001 From: Mathieu Kardous <84793247+mkardous-silabs@users.noreply.github.com> Date: Wed, 27 Nov 2024 13:59:59 -0500 Subject: [PATCH 09/26] Adds SubscriptionInfoProvider API to check if a given fabric has at least 1 subscription (#36627) * [SL-UP] Add fabric subscription check to the interaction model engine (#117) * Remove unwanted change * Restyle * Improve readability * Restyled by clang-format * Update src/app/SubscriptionsInfoProvider.h Co-authored-by: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> --------- Co-authored-by: Restyled.io Co-authored-by: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> --- src/app/InteractionModelEngine.cpp | 22 ++++ src/app/InteractionModelEngine.h | 2 + src/app/SubscriptionsInfoProvider.h | 10 ++ src/app/icd/server/tests/TestICDManager.cpp | 1 + src/app/tests/TestInteractionModelEngine.cpp | 121 +++++++++++++++++++ 5 files changed, 156 insertions(+) diff --git a/src/app/InteractionModelEngine.cpp b/src/app/InteractionModelEngine.cpp index 9b76dd31bff477..56acd096611565 100644 --- a/src/app/InteractionModelEngine.cpp +++ b/src/app/InteractionModelEngine.cpp @@ -462,6 +462,28 @@ bool InteractionModelEngine::SubjectHasPersistedSubscription(FabricIndex aFabric return persistedSubMatches; } +bool InteractionModelEngine::FabricHasAtLeastOneActiveSubscription(FabricIndex aFabricIndex) +{ + bool hasActiveSubscription = false; + mReadHandlers.ForEachActiveObject([aFabricIndex, &hasActiveSubscription](ReadHandler * handler) { + VerifyOrReturnValue(handler->IsType(ReadHandler::InteractionType::Subscribe), Loop::Continue); + + Access::SubjectDescriptor subject = handler->GetSubjectDescriptor(); + VerifyOrReturnValue(subject.fabricIndex == aFabricIndex, Loop::Continue); + + if ((subject.authMode == Access::AuthMode::kCase) && handler->IsActiveSubscription()) + { + // On first subscription found for fabric, we can immediately stop checking. + hasActiveSubscription = true; + return Loop::Break; + } + + return Loop::Continue; + }); + + return hasActiveSubscription; +} + void InteractionModelEngine::OnDone(CommandResponseSender & apResponderObj) { mCommandResponderObjs.ReleaseObject(&apResponderObj); diff --git a/src/app/InteractionModelEngine.h b/src/app/InteractionModelEngine.h index 3fa379129a0547..36aa2ccc6e3dd9 100644 --- a/src/app/InteractionModelEngine.h +++ b/src/app/InteractionModelEngine.h @@ -315,6 +315,8 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler, bool SubjectHasPersistedSubscription(FabricIndex aFabricIndex, NodeId subjectID) override; + bool FabricHasAtLeastOneActiveSubscription(FabricIndex aFabricIndex) override; + #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS /** * @brief Function decrements the number of subscriptions to resume counter - mNumOfSubscriptionsToResume. diff --git a/src/app/SubscriptionsInfoProvider.h b/src/app/SubscriptionsInfoProvider.h index cb8d470cbb234d..6fe383e1ffc2dc 100644 --- a/src/app/SubscriptionsInfoProvider.h +++ b/src/app/SubscriptionsInfoProvider.h @@ -61,6 +61,16 @@ class SubscriptionsInfoProvider * false subject doesn't have any persisted subscription with the device */ virtual bool SubjectHasPersistedSubscription(FabricIndex aFabricIndex, NodeId subjectID) = 0; + + /** + * @brief Check if a given fabric has at least 1 active subscription. + * + * @param aFabricIndex fabric index for which we want to validate is has at least one active subscription + * + * @return true fabric has at least one active subscription + * false fabric doesn't have any active subscription or failed to validate + */ + virtual bool FabricHasAtLeastOneActiveSubscription(FabricIndex aFabricIndex) = 0; }; } // namespace app diff --git a/src/app/icd/server/tests/TestICDManager.cpp b/src/app/icd/server/tests/TestICDManager.cpp index f6f999c1a36bca..4d0791c7149c54 100644 --- a/src/app/icd/server/tests/TestICDManager.cpp +++ b/src/app/icd/server/tests/TestICDManager.cpp @@ -122,6 +122,7 @@ class TestSubscriptionsInfoProvider : public SubscriptionsInfoProvider bool SubjectHasActiveSubscription(FabricIndex aFabricIndex, NodeId subject) { return mHasActiveSubscription; }; bool SubjectHasPersistedSubscription(FabricIndex aFabricIndex, NodeId subject) { return mHasPersistedSubscription; }; + bool FabricHasAtLeastOneActiveSubscription(FabricIndex aFabricIndex) { return false; }; private: bool mHasActiveSubscription = false; diff --git a/src/app/tests/TestInteractionModelEngine.cpp b/src/app/tests/TestInteractionModelEngine.cpp index acc19c12f44da0..88b3c07a6db178 100644 --- a/src/app/tests/TestInteractionModelEngine.cpp +++ b/src/app/tests/TestInteractionModelEngine.cpp @@ -68,6 +68,8 @@ class TestInteractionModelEngine : public chip::Test::AppContext void TestSubjectHasActiveSubscriptionSubWithCAT(); void TestSubscriptionResumptionTimer(); void TestDecrementNumSubscriptionsToResume(); + void TestFabricHasAtLeastOneActiveSubscription(); + void TestFabricHasAtLeastOneActiveSubscriptionWithMixedStates(); static int GetAttributePathListLength(SingleLinkedListNode * apattributePathParamsList); }; @@ -720,5 +722,124 @@ TEST_F_FROM_FIXTURE(TestInteractionModelEngine, TestDecrementNumSubscriptionsToR } #endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS +TEST_F_FROM_FIXTURE(TestInteractionModelEngine, TestFabricHasAtLeastOneActiveSubscription) +{ + NullReadHandlerCallback nullCallback; + InteractionModelEngine * engine = InteractionModelEngine::GetInstance(); + + FabricIndex fabricIndex1 = 1; + FabricIndex fabricIndex2 = 2; + + // Create ExchangeContexts + Messaging::ExchangeContext * exchangeCtx1 = NewExchangeToBob(nullptr, false); + ASSERT_TRUE(exchangeCtx1); + + Messaging::ExchangeContext * exchangeCtx2 = NewExchangeToAlice(nullptr, false); + ASSERT_TRUE(exchangeCtx2); + + // InteractionModelEngine init + EXPECT_EQ(CHIP_NO_ERROR, engine->Init(&GetExchangeManager(), &GetFabricTable(), reporting::GetDefaultReportScheduler())); + + // Verify that both fabrics have no active subscriptions + EXPECT_FALSE(engine->FabricHasAtLeastOneActiveSubscription(fabricIndex1)); + EXPECT_FALSE(engine->FabricHasAtLeastOneActiveSubscription(fabricIndex2)); + + // Create and setup readHandler 1 + ReadHandler * readHandler1 = + engine->GetReadHandlerPool().CreateObject(nullCallback, exchangeCtx1, ReadHandler::InteractionType::Subscribe, + reporting::GetDefaultReportScheduler(), CodegenDataModelProviderInstance()); + + // Verify that fabric 1 still doesn't have an active subscription + EXPECT_FALSE(engine->FabricHasAtLeastOneActiveSubscription(fabricIndex1)); + + // Set readHandler1 to active + readHandler1->SetStateFlag(ReadHandler::ReadHandlerFlags::ActiveSubscription, true); + + // Verify that fabric 1 has an active subscription + EXPECT_TRUE(engine->FabricHasAtLeastOneActiveSubscription(fabricIndex1)); + + // Verify that fabric 2 still doesn't have an active subscription + EXPECT_FALSE(engine->FabricHasAtLeastOneActiveSubscription(fabricIndex2)); + + // Create and setup readHandler 2 + ReadHandler * readHandler2 = + engine->GetReadHandlerPool().CreateObject(nullCallback, exchangeCtx2, ReadHandler::InteractionType::Subscribe, + reporting::GetDefaultReportScheduler(), CodegenDataModelProviderInstance()); + + // Set readHandler2 to active + readHandler2->SetStateFlag(ReadHandler::ReadHandlerFlags::ActiveSubscription, true); + + // Verify that fabric 2 has an active subscription + EXPECT_TRUE(engine->FabricHasAtLeastOneActiveSubscription(fabricIndex2)); + + // Clean up read handlers + engine->GetReadHandlerPool().ReleaseAll(); + + // Verify that both fabrics have no active subscriptions + EXPECT_FALSE(engine->FabricHasAtLeastOneActiveSubscription(fabricIndex1)); + EXPECT_FALSE(engine->FabricHasAtLeastOneActiveSubscription(fabricIndex2)); +} + +TEST_F_FROM_FIXTURE(TestInteractionModelEngine, TestFabricHasAtLeastOneActiveSubscriptionWithMixedStates) +{ + NullReadHandlerCallback nullCallback; + InteractionModelEngine * engine = InteractionModelEngine::GetInstance(); + + FabricIndex fabricIndex = 1; + + // Create ExchangeContexts + Messaging::ExchangeContext * exchangeCtx1 = NewExchangeToBob(nullptr, false); + ASSERT_TRUE(exchangeCtx1); + + Messaging::ExchangeContext * exchangeCtx2 = NewExchangeToBob(nullptr, false); + ASSERT_TRUE(exchangeCtx2); + + // InteractionModelEngine init + EXPECT_EQ(CHIP_NO_ERROR, engine->Init(&GetExchangeManager(), &GetFabricTable(), reporting::GetDefaultReportScheduler())); + + // Verify that the fabric has no active subscriptions + EXPECT_FALSE(engine->FabricHasAtLeastOneActiveSubscription(fabricIndex)); + + // Create and setup readHandler 1 + ReadHandler * readHandler1 = + engine->GetReadHandlerPool().CreateObject(nullCallback, exchangeCtx1, ReadHandler::InteractionType::Subscribe, + reporting::GetDefaultReportScheduler(), CodegenDataModelProviderInstance()); + + // Verify that the fabric still doesn't have an active subscription + EXPECT_FALSE(engine->FabricHasAtLeastOneActiveSubscription(fabricIndex)); + + // Set readHandler1 to active + readHandler1->SetStateFlag(ReadHandler::ReadHandlerFlags::ActiveSubscription, true); + + // Verify that the fabric has an active subscription + EXPECT_TRUE(engine->FabricHasAtLeastOneActiveSubscription(fabricIndex)); + + // Create and setup readHandler 2 + ReadHandler * readHandler2 = + engine->GetReadHandlerPool().CreateObject(nullCallback, exchangeCtx2, ReadHandler::InteractionType::Subscribe, + reporting::GetDefaultReportScheduler(), CodegenDataModelProviderInstance()); + + // Verify that the fabric still has an active subscription + EXPECT_TRUE(engine->FabricHasAtLeastOneActiveSubscription(fabricIndex)); + + // Set readHandler2 to inactive + readHandler2->SetStateFlag(ReadHandler::ReadHandlerFlags::ActiveSubscription, false); + + // Verify that the fabric still has an active subscription + EXPECT_TRUE(engine->FabricHasAtLeastOneActiveSubscription(fabricIndex)); + + // Set readHandler1 to inactive + readHandler1->SetStateFlag(ReadHandler::ReadHandlerFlags::ActiveSubscription, false); + + // Verify that the fabric doesn't have an active subscription + EXPECT_FALSE(engine->FabricHasAtLeastOneActiveSubscription(fabricIndex)); + + // Clean up read handlers + engine->GetReadHandlerPool().ReleaseAll(); + + // Verify that the fabric has no active subscriptions + EXPECT_FALSE(engine->FabricHasAtLeastOneActiveSubscription(fabricIndex)); +} + } // namespace app } // namespace chip From e18e289e799d679cbe0ff80fefb6cf5f49a253c9 Mon Sep 17 00:00:00 2001 From: shgutte <102281713+shgutte@users.noreply.github.com> Date: Thu, 28 Nov 2024 00:53:23 +0530 Subject: [PATCH 10/26] [Silabs] Adds refrigerator app matter shell support for change door state (#36548) * Added changes for the matter shell * Added support for the matter shell refrigerator door state * Added changes for the failure * Adds required comment changes * Added restyler changes * Adds changes according to comment --- .../silabs/src/EventHandlerLibShell.cpp | 4 +- examples/refrigerator-app/silabs/BUILD.gn | 4 + .../silabs/include/EventHandlerLibShell.h | 36 ++++ .../refrigerator-app/silabs/src/AppTask.cpp | 14 +- .../silabs/src/EventHandlerLibShell.cpp | 178 ++++++++++++++++++ 5 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 examples/refrigerator-app/silabs/include/EventHandlerLibShell.h create mode 100644 examples/refrigerator-app/silabs/src/EventHandlerLibShell.cpp diff --git a/examples/lock-app/silabs/src/EventHandlerLibShell.cpp b/examples/lock-app/silabs/src/EventHandlerLibShell.cpp index ef79290bd1961f..d9b9244fc6049a 100644 --- a/examples/lock-app/silabs/src/EventHandlerLibShell.cpp +++ b/examples/lock-app/silabs/src/EventHandlerLibShell.cpp @@ -99,7 +99,7 @@ CHIP_ERROR AlarmEventHandler(int argc, char ** argv) if (argc >= 2) { ChipLogError(Zcl, "Too many arguments provided to function %s, line %d", __func__, __LINE__); - return APP_ERROR_TOO_MANY_SHELL_ARGUMENTS; + return CHIP_ERROR_INVALID_ARGUMENT; } AlarmEventData * data = Platform::New(); @@ -131,7 +131,7 @@ CHIP_ERROR DoorStateEventHandler(int argc, char ** argv) if (argc >= 2) { ChipLogError(Zcl, "Too many arguments provided to function %s, line %d", __func__, __LINE__); - return APP_ERROR_TOO_MANY_SHELL_ARGUMENTS; + return CHIP_ERROR_INVALID_ARGUMENT; } DoorStateEventData * data = Platform::New(); diff --git a/examples/refrigerator-app/silabs/BUILD.gn b/examples/refrigerator-app/silabs/BUILD.gn index 200c909b1f2629..d902bb9e86da00 100644 --- a/examples/refrigerator-app/silabs/BUILD.gn +++ b/examples/refrigerator-app/silabs/BUILD.gn @@ -143,6 +143,10 @@ silabs_executable("refrigerator_app") { "src/refrigerator-and-temperature-controlled-cabinet-mode.cpp", ] + if (chip_build_libshell) { + sources += [ "src/EventHandlerLibShell.cpp" ] + } + if (use_temp_sensor) { sources += [ "${efr32_sdk_root}/hardware/driver/si70xx/src/sl_si70xx.c", diff --git a/examples/refrigerator-app/silabs/include/EventHandlerLibShell.h b/examples/refrigerator-app/silabs/include/EventHandlerLibShell.h new file mode 100644 index 00000000000000..5997b24d5b346c --- /dev/null +++ b/examples/refrigerator-app/silabs/include/EventHandlerLibShell.h @@ -0,0 +1,36 @@ +/* + * + * 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. + */ +#pragma once + +#include +#include +#include + +class EventData +{ +public: + chip::EventId eventId; +}; + +class RefrigeratorAlarmEventData : public EventData +{ +public: + chip::app::Clusters::RefrigeratorAlarm::AlarmBitmap doorState; +}; + +CHIP_ERROR RegisterRefrigeratorEvents(); +void EventWorkerFunction(intptr_t context); diff --git a/examples/refrigerator-app/silabs/src/AppTask.cpp b/examples/refrigerator-app/silabs/src/AppTask.cpp index d2def279beb754..c9dc451b71ddb1 100644 --- a/examples/refrigerator-app/silabs/src/AppTask.cpp +++ b/examples/refrigerator-app/silabs/src/AppTask.cpp @@ -24,7 +24,6 @@ #include "AppTask.h" #include "AppConfig.h" #include "AppEvent.h" - #include "LEDWidget.h" #ifdef DISPLAY_ENABLED @@ -35,6 +34,10 @@ #endif // QR_CODE_ENABLED #endif // DISPLAY_ENABLED +#if defined(ENABLE_CHIP_SHELL) +#include "EventHandlerLibShell.h" +#endif // ENABLE_CHIP_SHELL + #include #include #include @@ -94,6 +97,15 @@ CHIP_ERROR AppTask::Init() appError(err); } +#if defined(ENABLE_CHIP_SHELL) + err = RegisterRefrigeratorEvents(); + if (err != CHIP_NO_ERROR) + { + SILABS_LOG("RegisterRefrigeratorEvents() failed"); + appError(err); + } +#endif // ENABLE_CHIP_SHELL + return err; } diff --git a/examples/refrigerator-app/silabs/src/EventHandlerLibShell.cpp b/examples/refrigerator-app/silabs/src/EventHandlerLibShell.cpp new file mode 100644 index 00000000000000..212b2ac8d892ae --- /dev/null +++ b/examples/refrigerator-app/silabs/src/EventHandlerLibShell.cpp @@ -0,0 +1,178 @@ +/* + * + * 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 "EventHandlerLibShell.h" +#include "AppTask.h" +#include "lib/shell/Engine.h" +#include "lib/shell/commands/Help.h" + +#include "app/server/Server.h" +#include "platform/CHIPDeviceLayer.h" +#include + +constexpr uint8_t kRefEndpointId = 1; + +using namespace chip; +using namespace chip::app; +using namespace Clusters::RefrigeratorAlarm; +using namespace Clusters::TemperatureControl; +using Shell::Engine; +using Shell::shell_command_t; +using Shell::streamer_get; +using Shell::streamer_printf; + +Engine sShellRefrigeratorSubCommands; +Engine sShellRefrigeratorEventSubCommands; +Engine sShellRefrigeratorEventAlarmDoorSubCommands; + +/******************************************************** + * Refrigerator shell functions + *********************************************************/ + +CHIP_ERROR RefrigeratorHelpHandler(int argc, char ** argv) +{ + sShellRefrigeratorSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr); + return CHIP_NO_ERROR; +} + +CHIP_ERROR RefrigeratorCommandHandler(int argc, char ** argv) +{ + if (argc == 0) + { + return RefrigeratorHelpHandler(argc, argv); + } + + return sShellRefrigeratorSubCommands.ExecCommand(argc, argv); +} + +/******************************************************** + * Event shell functions + *********************************************************/ + +CHIP_ERROR EventHelpHandler(int argc, char ** argv) +{ + sShellRefrigeratorEventSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr); + return CHIP_NO_ERROR; +} + +CHIP_ERROR EventRefrigeratorCommandHandler(int argc, char ** argv) +{ + if (argc == 0) + { + return EventHelpHandler(argc, argv); + } + + return sShellRefrigeratorEventSubCommands.ExecCommand(argc, argv); +} + +/******************************************************** + * Alarm shell functions + *********************************************************/ + +CHIP_ERROR AlarmHelpHandler(int argc, char ** argv) +{ + sShellRefrigeratorEventAlarmDoorSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr); + return CHIP_NO_ERROR; +} + +CHIP_ERROR RefrigeratorDoorEventHandler(int argc, char ** argv) +{ + + if (argc == 0) + { + return AlarmHelpHandler(argc, argv); + } + if (argc >= 2) + { + ChipLogError(Shell, "Too many arguments"); + return CHIP_ERROR_INVALID_ARGUMENT; + } + + // Check if the argument is a valid integer + if (argv[0] == nullptr || !std::all_of(argv[0], argv[0] + strlen(argv[0]), ::isdigit)) + { + ChipLogError(Shell, "Invalid argument: Input must be a valid integer."); + return CHIP_ERROR_INVALID_ARGUMENT; + } + + // Convert the argument to an integer + int value = std::stoi(argv[0]); // Safe to use now, as we validated the input earlier + + RefrigeratorAlarmEventData * data = Platform::New(); + data->eventId = Events::Notify::Id; + data->doorState = static_cast(value); + + DeviceLayer::PlatformMgr().ScheduleWork(EventWorkerFunction, reinterpret_cast(data)); + + return CHIP_NO_ERROR; +} + +/** + * @brief configures Refrigerator matter shell + * + */ + +CHIP_ERROR RegisterRefrigeratorEvents() +{ + static const shell_command_t sRefrigeratorSubCommands[] = { + { &RefrigeratorHelpHandler, "help", "Usage: refrigeratoralarm " }, + { &EventRefrigeratorCommandHandler, "event", " Usage: refrigeratoralarm event " } + }; + + static const shell_command_t sRefrigeratorEventSubCommands[] = { + { &EventHelpHandler, "help", "Usage : refrigeratoralarm event " }, + { &RefrigeratorDoorEventHandler, "door-state-change", "Sends door state change event to Refrigerator app" } + }; + + static const shell_command_t sRefrigeratorEventAlarmDoorSubCommands[] = { + { &AlarmHelpHandler, "help", "Usage : Refrigerator event to change door state" } + }; + + static const shell_command_t sRefrigeratorCommand = { &RefrigeratorCommandHandler, "refrigeratoralarm", + "refrigerator alarm commands. Usage: refrigeratoralarm " }; + + sShellRefrigeratorEventAlarmDoorSubCommands.RegisterCommands(sRefrigeratorEventAlarmDoorSubCommands, + ArraySize(sRefrigeratorEventAlarmDoorSubCommands)); + sShellRefrigeratorEventSubCommands.RegisterCommands(sRefrigeratorEventSubCommands, ArraySize(sRefrigeratorEventSubCommands)); + sShellRefrigeratorSubCommands.RegisterCommands(sRefrigeratorSubCommands, ArraySize(sRefrigeratorSubCommands)); + + Engine::Root().RegisterCommands(&sRefrigeratorCommand, 1); + + return CHIP_NO_ERROR; +} + +void EventWorkerFunction(intptr_t context) +{ + VerifyOrReturn(reinterpret_cast(context) != nullptr, ChipLogError(Shell, "EventWorkerFunction - Invalid work data")); + EventData * data = reinterpret_cast(context); + + switch (data->eventId) + { + case Events::Notify::Id: { + RefrigeratorAlarmEventData * alarmData = reinterpret_cast(context); + RefrigeratorAlarmServer::Instance().SetStateValue(kRefEndpointId, alarmData->doorState); + break; + } + + default: { + ChipLogError(Zcl, "Invalid Event Id %s, line %d", __func__, __LINE__); + break; + } + } + // Free memory + Platform::Delete(data); +} From 63bc8a34ddb37a6632b44868a17155d85671cde6 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Wed, 27 Nov 2024 11:43:43 -0800 Subject: [PATCH 11/26] [Fabric-Sync] Fix segment fault during fabric device sync (#36656) --- examples/fabric-sync/admin/FabricAdmin.cpp | 8 ++++++-- examples/fabric-sync/main.cpp | 22 +++------------------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/examples/fabric-sync/admin/FabricAdmin.cpp b/examples/fabric-sync/admin/FabricAdmin.cpp index 3e96af42af8517..1716692691451a 100644 --- a/examples/fabric-sync/admin/FabricAdmin.cpp +++ b/examples/fabric-sync/admin/FabricAdmin.cpp @@ -44,8 +44,12 @@ CHIP_ERROR FabricAdmin::Init() auto engine = chip::app::InteractionModelEngine::GetInstance(); VerifyOrReturnError(engine != nullptr, CHIP_ERROR_INCORRECT_STATE); ReturnLogErrorOnFailure(IcdManager::Instance().Init(&sICDClientStorage, engine)); - ReturnLogErrorOnFailure(sCheckInHandler.Init(Controller::DeviceControllerFactory::GetInstance().GetSystemState()->ExchangeMgr(), - &sICDClientStorage, &IcdManager::Instance(), engine)); + + auto exchangeMgr = Controller::DeviceControllerFactory::GetInstance().GetSystemState()->ExchangeMgr(); + VerifyOrReturnError(exchangeMgr != nullptr, CHIP_ERROR_INCORRECT_STATE); + ReturnLogErrorOnFailure(sCheckInHandler.Init(exchangeMgr, &sICDClientStorage, &IcdManager::Instance(), engine)); + + ReturnLogErrorOnFailure(PairingManager::Instance().Init(GetDeviceCommissioner())); return CHIP_NO_ERROR; } diff --git a/examples/fabric-sync/main.cpp b/examples/fabric-sync/main.cpp index 1cad0d4965e84e..7eed75cce99f26 100644 --- a/examples/fabric-sync/main.cpp +++ b/examples/fabric-sync/main.cpp @@ -87,6 +87,9 @@ void ApplicationInit() CHIP_ERROR err = bridge::BridgeInit(&admin::FabricAdmin::Instance()); VerifyOrDieWithMsg(err == CHIP_NO_ERROR, NotSpecified, "Fabric-Sync: Failed to initialize bridge, error: %s", ErrorStr(err)); + + err = admin::FabricAdmin::Instance().Init(); + VerifyOrDieWithMsg(err == CHIP_NO_ERROR, NotSpecified, "Fabric-Sync: Failed to initialize admin, error: %s", ErrorStr(err)); } void ApplicationShutdown() @@ -112,24 +115,5 @@ int main(int argc, char * argv[]) ChipLinuxAppMainLoop(); - CHIP_ERROR err = admin::FabricAdmin::Instance().Init(); - - if (err != CHIP_NO_ERROR) - { - ChipLogProgress(NotSpecified, "Failed to init FabricAdmin: %s ", ErrorStr(err)); - - // End the program with non zero error code to indicate a error. - return 1; - } - - err = admin::PairingManager::Instance().Init(GetDeviceCommissioner()); - if (err != CHIP_NO_ERROR) - { - ChipLogProgress(NotSpecified, "Failed to init PairingManager: %s ", ErrorStr(err)); - - // End the program with non zero error code to indicate a error. - return 1; - } - return 0; } From 481270d86a048ad6b631fb55e5bd10acff104a26 Mon Sep 17 00:00:00 2001 From: Sergio Soares Date: Wed, 27 Nov 2024 15:04:18 -0500 Subject: [PATCH 12/26] energy-management-app: refactor WH and EVSE into separate endpoints and fix conformance issues (#36201) * Add missing Water Heater device to matter-devices.xml This PR adds the missing Water Heater device to matter-devices.xml. The description was generated using the Alchemy tool (https://github.com/project-chip/alchemy) with the following command: `alchemy zap --attribute="in-progress" --sdkRoot=./connectedhomeip/ --specRoot=./connectedhomeip-spec/ ./connectedhomeip-spec/src/device_types/WaterHeater.adoc` I manually fixed the device nae from `Matter Water Heater` to `Water Heater`. * zap regen * energy-management-app: Split WH and EVSE into 2 endpoints This PR refactors the energy-management-app into 2 separate endpoints (one for EVSE and another for WaterHeater). This is the first step in making this app spec-conformant. `TC_DeviceBasicComposition.py` failed on this app before this PR and now passes. Changes: * Split Water Heater and EVSE into two separate endpoints (1 and 2). Updated zap and code. * Dinamically disable unused endpoint at runtime. Based on the app choice (command line argument on linux or #define in ESP32 or SIlabs), initialize the clusters in the correct endpoint and disable the other endpoint. For example, for Water Heater, initialize clusters on endpoint 2 and disable endpoint 1 (EVSE). * Refactor/move the init code related to ElectricalSensor (PowerTopology, EPM and EEM) from inside EVSE into ElectricalSensorInit.h/.cpp so they can be easier to reuse by both WaterHeater and EVSE. * Refactor/move DEM cluster init code into its own file so it can be better reused outside EVSE. Test performed: 1. Check basic composition for EVSE: ``` scripts/run_in_python_env.sh out/python_env './scripts/tests/run_python_test.py --app ./out/linux-x64-energy-management-no-ble/chip-energy-management-app --app-args "--application evse --trace-to json:log" --script src/python_testing/TC_DeviceBasicComposition.py --script-args "--qr-code MT:-24J0AFN00KA0648G00"' ``` 2. Check basic composition for WaterHeater: ``` scripts/run_in_python_env.sh out/python_env './scripts/tests/run_python_test.py --app ./out/linux-x64-energy-management-no-ble/chip-energy-management-app --app-args "--application water-heater --trace-to json:log" --script src/python_testing/TC_DeviceBasicComposition.py --script-args "--qr-code MT:-24J0AFN00KA0648G00"' ``` 3. Check app against `TC_EEVSE_2_6.py`: ``` rm -f evse.bin; ./out/linux-x64-energy-management-no-ble/chip-energy-management-app --enable-key 000102030405060708090a0b0c0d0e0f --KVS evse.bin --featureSet 0x3d python src/python_testing/TC_EEVSE_2_6.py --endpoint 1 -m on-network -n 1234 -p 20202021 -d 3840 --hex-arg enableKey:000102030405060708090a0b0c0d0e0f ``` * Use anon namespace instead of static. * disable enpoint on esp32 and silabs * address Tennessee's PR feedback * Review suggestion: move GetMainAppEndpointId to another file * zap regen * fix matter-devices white space diffs * App now builds on all-clusters app * Fix typo on init * fix all-clusters breakage on esp32 * fix misuse of namespace in header * Fix breakage for silabs water heater * Update WaterHeater endpoint for CI tests This fixes REPL test CI breakage. * Update WaterHeater tests to endpoint 2 * Bumped ClusterRevisions Cluster 40 (0x28) BasicInformation - 3 -> 4 Cluster 47 (0x2f) PowerSource - 2 -> 3 Cluster 48 (0x30) GeneralCommissioning 1-> 2 Cluster 3 (0x03) Identify 4 -> 5 Cluster 153 (0x99) EnergyEvse 2 -> 3 Cluster 157 (0x9d) EnergyEvseMode 1-> 2 Cluster 159 (0x9f) DeviceEnergyManagementMode 1-> 2 * Update AccessControl featureMap to enable Extension attribute * Remove AccessControl extension attribute * Remove kStateForecastReporting from the default feature map That feature can't be enabled together with kPowerAdjustment. * Update TC_WHM_1_2 endpoint to 2 * Fix various conformance issues Remove PowerSource from root node and move to EP1/evse Bump cluster revisions where needed Fix device type descriptions for each EP Remove unused Thermostat cluster and added a TODO. We need to properly implement this cluster for this app for temperature control. * TC_WHM_1_2: Use endpoint id passed as argument instead of hardcoded --- .../src/energy-evse-stub.cpp | 5 + .../all-clusters-app/linux/main-common.cpp | 3 +- .../include/EnergyManagementAppCommonMain.h} | 16 + .../src/EnergyManagementAppCommonMain.cpp | 410 +++ .../src/DEMTestEventTriggers.cpp | 22 +- .../src/device-energy-management-mode.cpp | 23 +- .../include/EVSEManufacturerImpl.h | 4 +- .../energy-evse/include/EnergyEvseMain.h | 22 +- .../energy-evse/src/EVSEManufacturerImpl.cpp | 23 +- .../energy-evse/src/EnergyEvseMain.cpp | 359 +- .../energy-management-app.matter | 187 +- .../energy-management-app.zap | 3102 +++++++++++------ .../include/ElectricalSensorInit.h} | 21 +- .../energy-reporting/src/FakeReadings.cpp | 2 +- .../water-heater/include/WhmMain.h | 2 +- .../water-heater/src/WaterHeaterMain.cpp | 101 - .../water-heater/src/WhmDelegateImpl.cpp | 1 + .../water-heater/src/WhmMain.cpp | 12 +- .../water-heater/src/water-heater-mode.cpp | 10 +- .../energy-management-app/esp32/main/main.cpp | 34 +- examples/energy-management-app/linux/BUILD.gn | 2 +- examples/energy-management-app/linux/main.cpp | 38 +- .../energy-management-app/silabs/BUILD.gn | 2 +- .../silabs/src/AppTask.cpp | 32 +- src/python_testing/TC_EWATERHTR_2_1.py | 2 +- src/python_testing/TC_EWATERHTR_2_2.py | 2 +- src/python_testing/TC_EWATERHTR_2_3.py | 2 +- src/python_testing/TC_WHM_1_2.py | 2 +- src/python_testing/TC_WHM_2_1.py | 2 +- 29 files changed, 2802 insertions(+), 1641 deletions(-) rename examples/energy-management-app/energy-management-common/{device-energy-management/include/DEMDelegate.h => common/include/EnergyManagementAppCommonMain.h} (54%) create mode 100644 examples/energy-management-app/energy-management-common/common/src/EnergyManagementAppCommonMain.cpp rename examples/energy-management-app/energy-management-common/{water-heater/include/WaterHeaterMain.h => energy-reporting/include/ElectricalSensorInit.h} (55%) delete mode 100644 examples/energy-management-app/energy-management-common/water-heater/src/WaterHeaterMain.cpp diff --git a/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp b/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp index 6acc81ac285b65..efaa19600bb9e9 100644 --- a/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/energy-evse-stub.cpp @@ -26,6 +26,11 @@ static std::unique_ptr gDelegate; static std::unique_ptr gEvseTargetsDelegate; static std::unique_ptr gInstance; +EndpointId GetEnergyDeviceEndpointId() +{ + return chip::EndpointId(1); +} + void emberAfEnergyEvseClusterInitCallback(chip::EndpointId endpointId) { VerifyOrDie(endpointId == 1); // this cluster is only enabled for endpoint 1. diff --git a/examples/all-clusters-app/linux/main-common.cpp b/examples/all-clusters-app/linux/main-common.cpp index b62d154f0d58f7..22170885db1cbe 100644 --- a/examples/all-clusters-app/linux/main-common.cpp +++ b/examples/all-clusters-app/linux/main-common.cpp @@ -124,6 +124,7 @@ const Clusters::Descriptor::Structs::SemanticTagStruct::Type gEp3TagList[] = { { .tag = kTagSwitchesUp } }; const Clusters::Descriptor::Structs::SemanticTagStruct::Type gEp4TagList[] = { { .namespaceID = kNamespaceSwitches, .tag = kTagSwitchesDown } }; + } // namespace #ifdef MATTER_DM_PLUGIN_DISHWASHER_ALARM_SERVER @@ -256,7 +257,7 @@ void ApplicationInit() Clusters::ValveConfigurationAndControl::SetDefaultDelegate(chip::EndpointId(1), &sValveDelegate); Clusters::TimeSynchronization::SetDefaultDelegate(&sTimeSyncDelegate); - Clusters::WaterHeaterManagement::WhmApplicationInit(); + Clusters::WaterHeaterManagement::WhmApplicationInit(chip::EndpointId(1)); SetTagList(/* endpoint= */ 0, Span(gEp0TagList)); SetTagList(/* endpoint= */ 1, Span(gEp1TagList)); diff --git a/examples/energy-management-app/energy-management-common/device-energy-management/include/DEMDelegate.h b/examples/energy-management-app/energy-management-common/common/include/EnergyManagementAppCommonMain.h similarity index 54% rename from examples/energy-management-app/energy-management-common/device-energy-management/include/DEMDelegate.h rename to examples/energy-management-app/energy-management-common/common/include/EnergyManagementAppCommonMain.h index ac5cc5000e71b9..1a9ff734b6596f 100644 --- a/examples/energy-management-app/energy-management-common/device-energy-management/include/DEMDelegate.h +++ b/examples/energy-management-app/energy-management-common/common/include/EnergyManagementAppCommonMain.h @@ -19,5 +19,21 @@ #pragma once #include +#include +#include +#include +#include +// This app is configured by default with EP1 for EVSE and EP2 for WaterHeater, with only one endpoint +// enabled. On linux, there's a command line argument (--application) to dynamically enable +// "evse|water-heater", i.e. EP1 or EP2. On other platforms, it's a build time definition (#define). +chip::EndpointId GetEnergyDeviceEndpointId(); + +// The DEM Delegate is used for the TestEventTriggers chip::app::Clusters::DeviceEnergyManagement::DeviceEnergyManagementDelegate * GetDEMDelegate(); + +void EvseApplicationInit(); +void EvseApplicationShutdown(); + +void WaterHeaterApplicationInit(); +void WaterHeaterApplicationShutdown(); diff --git a/examples/energy-management-app/energy-management-common/common/src/EnergyManagementAppCommonMain.cpp b/examples/energy-management-app/energy-management-common/common/src/EnergyManagementAppCommonMain.cpp new file mode 100644 index 00000000000000..e35dbf7b05bd9f --- /dev/null +++ b/examples/energy-management-app/energy-management-common/common/src/EnergyManagementAppCommonMain.cpp @@ -0,0 +1,410 @@ +/* + * + * 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. + */ + +#include "EnergyManagementAppCommonMain.h" +#include "EnergyManagementAppCmdLineOptions.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::DataModel; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::DeviceEnergyManagement; +using namespace chip::app::Clusters::ElectricalPowerMeasurement; +using namespace chip::app::Clusters::ElectricalEnergyMeasurement; +using namespace chip::app::Clusters::PowerTopology; +using namespace chip::app::Clusters::WaterHeaterManagement; + +namespace { + +std::unique_ptr gDEMDelegate; +std::unique_ptr gDEMInstance; +std::unique_ptr gEPMDelegate; +std::unique_ptr gEPMInstance; +std::unique_ptr gPTDelegate; +std::unique_ptr gPTInstance; +// Electrical Energy Measurement cluster uses ember to initialise +std::unique_ptr gEEMAttrAccess; +bool gCommonClustersInitialized = false; + +/* + * @brief Creates a Delegate and Instance for PowerTopology clusters + * + * The Instance is a container around the Delegate, so + * create the Delegate first, then wrap it in the Instance + * Then call the Instance->Init() to register the attribute and command handlers + */ +CHIP_ERROR PowerTopologyInit(chip::EndpointId endpointId) +{ + CHIP_ERROR err; + + if (gPTDelegate || gPTInstance) + { + ChipLogError(AppServer, "PowerTopology Instance or Delegate already exist."); + return CHIP_ERROR_INCORRECT_STATE; + } + + gPTDelegate = std::make_unique(); + if (!gPTDelegate) + { + ChipLogError(AppServer, "Failed to allocate memory for PowerTopology Delegate"); + return CHIP_ERROR_NO_MEMORY; + } + + gPTInstance = std::make_unique( + EndpointId(endpointId), *gPTDelegate, BitMask(PowerTopology::Feature::kNodeTopology), + BitMask(0)); + + if (!gPTInstance) + { + ChipLogError(AppServer, "Failed to allocate memory for PowerTopology Instance"); + gPTDelegate.reset(); + return CHIP_ERROR_NO_MEMORY; + } + + err = gPTInstance->Init(); /* Register Attribute & Command handlers */ + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "Init failed on gPTInstance"); + gPTInstance.reset(); + gPTDelegate.reset(); + return err; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR PowerTopologyShutdown() +{ + /* Do this in the order Instance first, then delegate + * Ensure we call the Instance->Shutdown to free attribute & command handlers first + */ + if (gPTInstance) + { + /* deregister attribute & command handlers */ + gPTInstance->Shutdown(); + gPTInstance.reset(); + } + + if (gPTDelegate) + { + gPTDelegate.reset(); + } + + return CHIP_NO_ERROR; +} + +/* + * @brief Creates a Delegate and Instance for Electrical Power Measurement cluster + * + * The Instance is a container around the Delegate, so + * create the Delegate first, then wrap it in the Instance + * Then call the Instance->Init() to register the attribute and command handlers + */ +CHIP_ERROR ElectricalPowerMeasurementInit(chip::EndpointId endpointId) +{ + CHIP_ERROR err; + + if (gEPMDelegate || gEPMInstance) + { + ChipLogError(AppServer, "EPM Instance or Delegate already exist."); + return CHIP_ERROR_INCORRECT_STATE; + } + + gEPMDelegate = std::make_unique(); + if (!gEPMDelegate) + { + ChipLogError(AppServer, "Failed to allocate memory for EPM Delegate"); + return CHIP_ERROR_NO_MEMORY; + } + + /* Manufacturer may optionally not support all features, commands & attributes */ + /* Turning on all optional features and attributes for test certification purposes */ + gEPMInstance = std::make_unique( + EndpointId(endpointId), *gEPMDelegate, + BitMask( + ElectricalPowerMeasurement::Feature::kDirectCurrent, ElectricalPowerMeasurement::Feature::kAlternatingCurrent, + ElectricalPowerMeasurement::Feature::kPolyphasePower, ElectricalPowerMeasurement::Feature::kHarmonics, + ElectricalPowerMeasurement::Feature::kPowerQuality), + BitMask( + ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRanges, + ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeVoltage, + ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeActiveCurrent, + ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeReactiveCurrent, + ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeApparentCurrent, + ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeReactivePower, + ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeApparentPower, + ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRMSVoltage, + ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRMSCurrent, + ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRMSPower, + ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeFrequency, + ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributePowerFactor, + ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeNeutralCurrent)); + + if (!gEPMInstance) + { + ChipLogError(AppServer, "Failed to allocate memory for EPM Instance"); + gEPMDelegate.reset(); + return CHIP_ERROR_NO_MEMORY; + } + + err = gEPMInstance->Init(); /* Register Attribute & Command handlers */ + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "Init failed on gEPMInstance"); + gEPMInstance.reset(); + gEPMDelegate.reset(); + return err; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ElectricalPowerMeasurementShutdown() +{ + /* Do this in the order Instance first, then delegate + * Ensure we call the Instance->Shutdown to free attribute & command handlers first + */ + if (gEPMInstance) + { + /* deregister attribute & command handlers */ + gEPMInstance->Shutdown(); + gEPMInstance.reset(); + } + + if (gEPMDelegate) + { + gEPMDelegate.reset(); + } + + return CHIP_NO_ERROR; +} + +/* + * @brief Creates a Delegate and Instance for DEM + * + * The Instance is a container around the Delegate, so + * create the Delegate first, then wrap it in the Instance + * Then call the Instance->Init() to register the attribute and command handlers + */ +CHIP_ERROR DeviceEnergyManagementInit(chip::EndpointId endpointId) +{ + if (gDEMDelegate || gDEMInstance) + { + ChipLogError(AppServer, "DEM Instance or Delegate already exist."); + return CHIP_ERROR_INCORRECT_STATE; + } + + gDEMDelegate = std::make_unique(); + if (!gDEMDelegate) + { + ChipLogError(AppServer, "Failed to allocate memory for DeviceEnergyManagementDelegate"); + return CHIP_ERROR_NO_MEMORY; + } + + chip::BitMask featureMap = GetFeatureMapFromCmdLine(); + + /* Manufacturer may optionally not support all features, commands & attributes */ + gDEMInstance = std::make_unique(endpointId, *gDEMDelegate, featureMap); + + if (!gDEMInstance) + { + ChipLogError(AppServer, "Failed to allocate memory for DeviceEnergyManagementManager"); + gDEMDelegate.reset(); + return CHIP_ERROR_NO_MEMORY; + } + + gDEMDelegate->SetDeviceEnergyManagementInstance(*gDEMInstance); + + CHIP_ERROR err = gDEMInstance->Init(); /* Register Attribute & Command handlers */ + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "Init failed on gDEMInstance"); + gDEMInstance.reset(); + gDEMDelegate.reset(); + return err; + } + + return CHIP_NO_ERROR; +} + +void DeviceEnergyManagementShutdown() +{ + /* Do this in the order Instance first, then delegate + * Ensure we call the Instance->Shutdown to free attribute & command handlers first + */ + if (gDEMInstance) + { + /* deregister attribute & command handlers */ + gDEMInstance->Shutdown(); + gDEMInstance.reset(); + } + if (gDEMDelegate) + { + gDEMDelegate.reset(); + } +} + +CHIP_ERROR EnergyManagementCommonClustersInit(chip::EndpointId endpointId) +{ + if (!gCommonClustersInitialized) + { + DeviceEnergyManagementInit(endpointId); + ElectricalPowerMeasurementInit(endpointId); + PowerTopologyInit(endpointId); + } + VerifyOrReturnError(gDEMDelegate && gDEMInstance, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(gEPMDelegate && gEPMInstance, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(gPTDelegate && gPTInstance, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(gEEMAttrAccess, CHIP_ERROR_INCORRECT_STATE); + gCommonClustersInitialized = true; + return CHIP_NO_ERROR; +} + +} // namespace + +void emberAfElectricalEnergyMeasurementClusterInitCallback(chip::EndpointId endpointId) +{ + /* emberAfElectricalEnergyMeasurementClusterInitCallback() is called for all endpoints + that include the EEM endpoint (even the one we disable dynamically). So here, we only + proceed when it's called for the right endpoint determined by GetEnergyDeviceEndpointId(). + */ + if (endpointId != GetEnergyDeviceEndpointId()) + { + return; + } + + VerifyOrDie(!gEEMAttrAccess); // Ensure it's not initialized yet. + + gEEMAttrAccess = std::make_unique( + BitMask( + ElectricalEnergyMeasurement::Feature::kImportedEnergy, ElectricalEnergyMeasurement::Feature::kExportedEnergy, + ElectricalEnergyMeasurement::Feature::kCumulativeEnergy, ElectricalEnergyMeasurement::Feature::kPeriodicEnergy), + BitMask( + ElectricalEnergyMeasurement::OptionalAttributes::kOptionalAttributeCumulativeEnergyReset)); + + // Create an accuracy entry which is between +/-0.5 and +/- 5% across the range of all possible energy readings + ElectricalEnergyMeasurement::Structs::MeasurementAccuracyRangeStruct::Type energyAccuracyRanges[] = { + { .rangeMin = 0, + .rangeMax = 1'000'000'000'000'000, // 1 million Mwh + .percentMax = MakeOptional(static_cast(500)), + .percentMin = MakeOptional(static_cast(50)) } + }; + + ElectricalEnergyMeasurement::Structs::MeasurementAccuracyStruct::Type accuracy = { + .measurementType = MeasurementTypeEnum::kElectricalEnergy, + .measured = true, + .minMeasuredValue = 0, + .maxMeasuredValue = 1'000'000'000'000'000, // 1 million Mwh + .accuracyRanges = + DataModel::List(energyAccuracyRanges) + }; + + // Example of setting CumulativeEnergyReset structure - for now set these to 0 + // but the manufacturer may want to store these in non volatile storage for timestamp (based on epoch_s) + ElectricalEnergyMeasurement::Structs::CumulativeEnergyResetStruct::Type resetStruct = { + .importedResetTimestamp = MakeOptional(MakeNullable(static_cast(0))), + .exportedResetTimestamp = MakeOptional(MakeNullable(static_cast(0))), + .importedResetSystime = MakeOptional(MakeNullable(static_cast(0))), + .exportedResetSystime = MakeOptional(MakeNullable(static_cast(0))), + }; + + if (gEEMAttrAccess) + { + gEEMAttrAccess->Init(); + + SetMeasurementAccuracy(endpointId, accuracy); + SetCumulativeReset(endpointId, MakeOptional(resetStruct)); + } +} + +DeviceEnergyManagement::DeviceEnergyManagementDelegate * GetDEMDelegate() +{ + VerifyOrDieWithMsg(gDEMDelegate.get() != nullptr, AppServer, "DEM Delegate is null"); + + return gDEMDelegate.get(); +} + +void EvseApplicationInit() +{ + auto endpointId = GetEnergyDeviceEndpointId(); + VerifyOrDie(EnergyManagementCommonClustersInit(endpointId) == CHIP_NO_ERROR); + VerifyOrDie(EnergyEvseInit(endpointId) == CHIP_NO_ERROR); + VerifyOrDie(EVSEManufacturerInit(endpointId, *gEPMInstance.get(), *gPTInstance.get(), *gDEMInstance.get(), + *gDEMDelegate.get()) == CHIP_NO_ERROR); +} + +void EvseApplicationShutdown() +{ + ChipLogDetail(AppServer, "Energy Management App (EVSE): EvseApplicationShutdown()"); + + /* Shutdown in reverse order that they were created */ + EVSEManufacturerShutdown(); /* Free the EVSEManufacturer */ + PowerTopologyShutdown(); /* Free the PowerTopology */ + ElectricalPowerMeasurementShutdown(); /* Free the Electrical Power Measurement */ + EnergyEvseShutdown(); /* Free the EnergyEvse */ + DeviceEnergyManagementShutdown(); /* Free the DEM */ + + Clusters::DeviceEnergyManagementMode::Shutdown(); + Clusters::EnergyEvseMode::Shutdown(); +} + +void WaterHeaterApplicationInit() +{ + auto endpointId = GetEnergyDeviceEndpointId(); + VerifyOrDie(EnergyManagementCommonClustersInit(endpointId) == CHIP_NO_ERROR); + VerifyOrDie(WhmApplicationInit(endpointId) == CHIP_NO_ERROR); + + /* For Device Energy Management we need the ESA to be Online and ready to accept commands */ + gDEMDelegate->SetESAState(ESAStateEnum::kOnline); + gDEMDelegate->SetESAType(ESATypeEnum::kWaterHeating); + gDEMDelegate->SetDEMManufacturerDelegate(*GetWhmManufacturer()); + + // Set the abs min and max power + gDEMDelegate->SetAbsMinPower(1200000); // 1.2KW + gDEMDelegate->SetAbsMaxPower(7600000); // 7.6KW +} + +void WaterHeaterApplicationShutdown() +{ + ChipLogDetail(AppServer, "Energy Management App (WaterHeater): WaterHeaterShutdown()"); + + /* Shutdown in reverse order that they were created */ + PowerTopologyShutdown(); /* Free the PowerTopology */ + ElectricalPowerMeasurementShutdown(); /* Free the Energy Meter */ + DeviceEnergyManagementShutdown(); /* Free the DEM */ + WhmApplicationShutdown(); + + Clusters::DeviceEnergyManagementMode::Shutdown(); + Clusters::WaterHeaterMode::Shutdown(); +} diff --git a/examples/energy-management-app/energy-management-common/device-energy-management/src/DEMTestEventTriggers.cpp b/examples/energy-management-app/energy-management-common/device-energy-management/src/DEMTestEventTriggers.cpp index 58258b73cd50e8..23ed2afe1b994d 100644 --- a/examples/energy-management-app/energy-management-common/device-energy-management/src/DEMTestEventTriggers.cpp +++ b/examples/energy-management-app/energy-management-common/device-energy-management/src/DEMTestEventTriggers.cpp @@ -16,9 +16,10 @@ * limitations under the License. */ -#include #include +#include #include +#include #include @@ -28,19 +29,22 @@ using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; using namespace chip::app::Clusters::DeviceEnergyManagement; +namespace { -static constexpr uint16_t MAX_SLOTS = 10; -static constexpr uint16_t MAX_POWER_ADJUSTMENTS = 5; +constexpr uint16_t MAX_SLOTS = 10; +constexpr uint16_t MAX_POWER_ADJUSTMENTS = 5; -static chip::app::Clusters::DeviceEnergyManagement::Structs::SlotStruct::Type sSlots[MAX_SLOTS]; -static chip::app::Clusters::DeviceEnergyManagement::Structs::ForecastStruct::Type sForecastStruct; -static chip::app::DataModel::Nullable sForecast; +chip::app::Clusters::DeviceEnergyManagement::Structs::SlotStruct::Type sSlots[MAX_SLOTS]; +chip::app::Clusters::DeviceEnergyManagement::Structs::ForecastStruct::Type sForecastStruct; +chip::app::DataModel::Nullable sForecast; -static chip::app::Clusters::DeviceEnergyManagement::Structs::PowerAdjustStruct::Type sPowerAdjustments[MAX_POWER_ADJUSTMENTS]; -static chip::app::Clusters::DeviceEnergyManagement::Structs::PowerAdjustCapabilityStruct::Type sPowerAdjustCapabilityStruct; -static chip::app::DataModel::Nullable +chip::app::Clusters::DeviceEnergyManagement::Structs::PowerAdjustStruct::Type sPowerAdjustments[MAX_POWER_ADJUSTMENTS]; +chip::app::Clusters::DeviceEnergyManagement::Structs::PowerAdjustCapabilityStruct::Type sPowerAdjustCapabilityStruct; +chip::app::DataModel::Nullable sPowerAdjustmentCapability; +} // namespace + CHIP_ERROR ConfigureForecast(uint16_t numSlots) { uint32_t chipEpoch = 0; diff --git a/examples/energy-management-app/energy-management-common/device-energy-management/src/device-energy-management-mode.cpp b/examples/energy-management-app/energy-management-common/device-energy-management/src/device-energy-management-mode.cpp index d993e5c163ada1..330c0b0e389512 100644 --- a/examples/energy-management-app/energy-management-common/device-energy-management/src/device-energy-management-mode.cpp +++ b/examples/energy-management-app/energy-management-common/device-energy-management/src/device-energy-management-mode.cpp @@ -16,19 +16,27 @@ * limitations under the License. */ +#include +#include #include #include using namespace chip::app::Clusters; using namespace chip::app::Clusters::DeviceEnergyManagementMode; +using namespace chip::app::Clusters::DeviceEnergyManagement; + using chip::Protocols::InteractionModel::Status; template using List = chip::app::DataModel::List; using ModeTagStructType = chip::app::Clusters::detail::Structs::ModeTagStruct::Type; +namespace { + static std::unique_ptr gDeviceEnergyManagementModeDelegate; static std::unique_ptr gDeviceEnergyManagementModeInstance; +} // namespace + CHIP_ERROR DeviceEnergyManagementModeDelegate::Init() { return CHIP_NO_ERROR; @@ -77,11 +85,6 @@ CHIP_ERROR DeviceEnergyManagementModeDelegate::GetModeTagsByIndex(uint8_t modeIn return CHIP_NO_ERROR; } -ModeBase::Instance * DeviceEnergyManagementMode::Instance() -{ - return gDeviceEnergyManagementModeInstance.get(); -} - void DeviceEnergyManagementMode::Shutdown() { gDeviceEnergyManagementModeInstance.reset(); @@ -90,6 +93,16 @@ void DeviceEnergyManagementMode::Shutdown() void emberAfDeviceEnergyManagementModeClusterInitCallback(chip::EndpointId endpointId) { + /* emberAfDeviceEnergyManagementModeClusterInitCallback() is called for all endpoints + that include this cluster (even the one we disable dynamically). So here, we only + proceed when it's called for the right endpoint determined by GetEnergyDeviceEndpointId() + (a cmd line argument on linux or #define on other platforms). + */ + if (endpointId != GetEnergyDeviceEndpointId()) + { + return; + } + VerifyOrDie(!gDeviceEnergyManagementModeDelegate && !gDeviceEnergyManagementModeInstance); gDeviceEnergyManagementModeDelegate = std::make_unique(); gDeviceEnergyManagementModeInstance = std::make_unique(gDeviceEnergyManagementModeDelegate.get(), diff --git a/examples/energy-management-app/energy-management-common/energy-evse/include/EVSEManufacturerImpl.h b/examples/energy-management-app/energy-management-common/energy-evse/include/EVSEManufacturerImpl.h index c802cf8e047dcb..4f8c9530caeeb6 100644 --- a/examples/energy-management-app/energy-management-common/energy-evse/include/EVSEManufacturerImpl.h +++ b/examples/energy-management-app/energy-management-common/energy-evse/include/EVSEManufacturerImpl.h @@ -117,7 +117,7 @@ class EVSEManufacturer : public DEMManufacturerDelegate /** * @brief Called at start up to apply hardware settings */ - CHIP_ERROR Init(); + CHIP_ERROR Init(chip::EndpointId powerSourceEndpointId); /** * @brief Called at shutdown @@ -143,7 +143,7 @@ class EVSEManufacturer : public DEMManufacturerDelegate /** * @brief Allows a client application to initialise the PowerSource cluster */ - CHIP_ERROR InitializePowerSourceCluster(); + CHIP_ERROR InitializePowerSourceCluster(chip::EndpointId endpointId); /** * @brief Allows a client application to send in power readings into the system diff --git a/examples/energy-management-app/energy-management-common/energy-evse/include/EnergyEvseMain.h b/examples/energy-management-app/energy-management-common/energy-evse/include/EnergyEvseMain.h index 07dce510e9b38c..a959267beadfd3 100644 --- a/examples/energy-management-app/energy-management-common/energy-evse/include/EnergyEvseMain.h +++ b/examples/energy-management-app/energy-management-common/energy-evse/include/EnergyEvseMain.h @@ -18,16 +18,18 @@ #pragma once +#include +#include +#include +#include #include -void EvseApplicationInit(); -void EvseApplicationShutdown(); +CHIP_ERROR EnergyEvseInit(chip::EndpointId endpointId); +CHIP_ERROR EnergyEvseShutdown(); -CHIP_ERROR DeviceEnergyManagementInit(); -CHIP_ERROR DeviceEnergyManagementShutdown(); - -CHIP_ERROR EnergyMeterInit(); -CHIP_ERROR EnergyMeterShutdown(); - -CHIP_ERROR PowerTopologyInit(); -CHIP_ERROR PowerTopologyShutdown(); +CHIP_ERROR EVSEManufacturerInit(chip::EndpointId powerSourceEndpointId, + chip::app::Clusters::ElectricalPowerMeasurement::ElectricalPowerMeasurementInstance & epmInstance, + chip::app::Clusters::PowerTopology::PowerTopologyInstance & ptInstance, + chip::app::Clusters::DeviceEnergyManagementManager & demInstance, + chip::app::Clusters::DeviceEnergyManagement::DeviceEnergyManagementDelegate & demDelegate); +CHIP_ERROR EVSEManufacturerShutdown(); diff --git a/examples/energy-management-app/energy-management-common/energy-evse/src/EVSEManufacturerImpl.cpp b/examples/energy-management-app/energy-management-common/energy-evse/src/EVSEManufacturerImpl.cpp index 0cb5a0fe98ce02..372a6472d2c7a5 100644 --- a/examples/energy-management-app/energy-management-common/energy-evse/src/EVSEManufacturerImpl.cpp +++ b/examples/energy-management-app/energy-management-common/energy-evse/src/EVSEManufacturerImpl.cpp @@ -47,7 +47,7 @@ using namespace chip::app::Clusters::PowerSource::Attributes; using Protocols::InteractionModel::Status; -CHIP_ERROR EVSEManufacturer::Init() +CHIP_ERROR EVSEManufacturer::Init(chip::EndpointId powerSourceEndpointId) { /* Manufacturers should modify this to do any custom initialisation */ @@ -63,7 +63,7 @@ CHIP_ERROR EVSEManufacturer::Init() ReturnErrorOnFailure(InitializePowerMeasurementCluster()); - ReturnErrorOnFailure(InitializePowerSourceCluster()); + ReturnErrorOnFailure(InitializePowerSourceCluster(powerSourceEndpointId)); DeviceEnergyManagementDelegate * dem = GetEvseManufacturer()->GetDEMDelegate(); VerifyOrReturnLogError(dem != nullptr, CHIP_ERROR_UNINITIALIZED); @@ -352,31 +352,30 @@ CHIP_ERROR EVSEManufacturer::InitializePowerMeasurementCluster() /** * @brief Allows a client application to initialise the PowerSource cluster */ -CHIP_ERROR EVSEManufacturer::InitializePowerSourceCluster() +CHIP_ERROR EVSEManufacturer::InitializePowerSourceCluster(chip::EndpointId endpointId) { Protocols::InteractionModel::Status status; - status = PowerSource::Attributes::Status::Set(EndpointId(0) /*RootNode*/, PowerSourceStatusEnum::kActive); + status = PowerSource::Attributes::Status::Set(endpointId, PowerSourceStatusEnum::kActive); VerifyOrReturnError(status == Protocols::InteractionModel::Status::Success, CHIP_ERROR_INTERNAL); - status = - PowerSource::Attributes::FeatureMap::Set(EndpointId(0 /*RootNode*/), static_cast(PowerSource::Feature::kWired)); + status = PowerSource::Attributes::FeatureMap::Set(endpointId, static_cast(PowerSource::Feature::kWired)); VerifyOrReturnError(status == Protocols::InteractionModel::Status::Success, CHIP_ERROR_INTERNAL); - status = PowerSource::Attributes::WiredNominalVoltage::Set(EndpointId(0 /*RootNode*/), 230'000); // 230V in mv + status = PowerSource::Attributes::WiredNominalVoltage::Set(endpointId, 230'000); // 230V in mv VerifyOrReturnError(status == Protocols::InteractionModel::Status::Success, CHIP_ERROR_INTERNAL); - status = PowerSource::Attributes::WiredMaximumCurrent::Set(EndpointId(0 /*RootNode*/), 32'000); // 32A in mA + status = PowerSource::Attributes::WiredMaximumCurrent::Set(endpointId, 32'000); // 32A in mA VerifyOrReturnError(status == Protocols::InteractionModel::Status::Success, CHIP_ERROR_INTERNAL); - status = PowerSource::Attributes::WiredCurrentType::Set(EndpointId(0 /*RootNode*/), PowerSource::WiredCurrentTypeEnum::kAc); + status = PowerSource::Attributes::WiredCurrentType::Set(endpointId, PowerSource::WiredCurrentTypeEnum::kAc); VerifyOrReturnError(status == Protocols::InteractionModel::Status::Success, CHIP_ERROR_INTERNAL); - status = PowerSource::Attributes::Description::Set(EndpointId(0 /*RootNode*/), CharSpan::fromCharString("Primary Mains Power")); + status = PowerSource::Attributes::Description::Set(endpointId, CharSpan::fromCharString("Primary Mains Power")); VerifyOrReturnError(status == Protocols::InteractionModel::Status::Success, CHIP_ERROR_INTERNAL); - chip::EndpointId endpointArray[] = { 1 /* EVSE Endpoint */ }; + chip::EndpointId endpointArray[] = { endpointId }; Span endpointList = Span(endpointArray); // Note per API - we do not need to maintain the span after the SetEndpointList has been called // since it takes a copy (see power-source-server.cpp) - PowerSourceServer::Instance().SetEndpointList(0 /* Root Node */, endpointList); + PowerSourceServer::Instance().SetEndpointList(endpointId, endpointList); return CHIP_NO_ERROR; } diff --git a/examples/energy-management-app/energy-management-common/energy-evse/src/EnergyEvseMain.cpp b/examples/energy-management-app/energy-management-common/energy-evse/src/EnergyEvseMain.cpp index 8e900c0948008a..8c3383db337113 100644 --- a/examples/energy-management-app/energy-management-common/energy-evse/src/EnergyEvseMain.cpp +++ b/examples/energy-management-app/energy-management-common/energy-evse/src/EnergyEvseMain.cpp @@ -21,7 +21,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -31,115 +33,30 @@ #include #include #include -#include #include #include #include -#define ENERGY_EVSE_ENDPOINT 1 - using namespace chip; using namespace chip::app; using namespace chip::app::DataModel; using namespace chip::app::Clusters; -using namespace chip::app::Clusters::EnergyEvse; using namespace chip::app::Clusters::DeviceEnergyManagement; using namespace chip::app::Clusters::ElectricalPowerMeasurement; using namespace chip::app::Clusters::ElectricalEnergyMeasurement; +using namespace chip::app::Clusters::EnergyEvse; using namespace chip::app::Clusters::PowerTopology; static std::unique_ptr gEvseDelegate; static std::unique_ptr gEvseTargetsDelegate; static std::unique_ptr gEvseInstance; -static std::unique_ptr gDEMDelegate; -static std::unique_ptr gDEMInstance; static std::unique_ptr gEvseManufacturer; -static std::unique_ptr gEPMDelegate; -static std::unique_ptr gEPMInstance; -// Electrical Energy Measurement cluster uses ember to initialise -static std::unique_ptr gEEMAttrAccess; - -static std::unique_ptr gPTDelegate; -static std::unique_ptr gPTInstance; EVSEManufacturer * EnergyEvse::GetEvseManufacturer() { return gEvseManufacturer.get(); } -DeviceEnergyManagement::DeviceEnergyManagementDelegate * GetDEMDelegate() -{ - VerifyOrDieWithMsg(gDEMDelegate.get() != nullptr, AppServer, "DEM Delegate is null"); - - return gDEMDelegate.get(); -} - -/* - * @brief Creates a Delegate and Instance for DEM - * - * The Instance is a container around the Delegate, so - * create the Delegate first, then wrap it in the Instance - * Then call the Instance->Init() to register the attribute and command handlers - */ -CHIP_ERROR DeviceEnergyManagementInit() -{ - if (gDEMDelegate || gDEMInstance) - { - ChipLogError(AppServer, "DEM Instance or Delegate already exist."); - return CHIP_ERROR_INCORRECT_STATE; - } - - gDEMDelegate = std::make_unique(); - if (!gDEMDelegate) - { - ChipLogError(AppServer, "Failed to allocate memory for DeviceEnergyManagementDelegate"); - return CHIP_ERROR_NO_MEMORY; - } - - BitMask featureMap = GetFeatureMapFromCmdLine(); - - /* Manufacturer may optionally not support all features, commands & attributes */ - gDEMInstance = std::make_unique(EndpointId(ENERGY_EVSE_ENDPOINT), *gDEMDelegate, featureMap); - - if (!gDEMInstance) - { - ChipLogError(AppServer, "Failed to allocate memory for DeviceEnergyManagementManager"); - gDEMDelegate.reset(); - return CHIP_ERROR_NO_MEMORY; - } - - gDEMDelegate->SetDeviceEnergyManagementInstance(*gDEMInstance); - - CHIP_ERROR err = gDEMInstance->Init(); /* Register Attribute & Command handlers */ - if (err != CHIP_NO_ERROR) - { - ChipLogError(AppServer, "Init failed on gDEMInstance"); - gDEMInstance.reset(); - gDEMDelegate.reset(); - return err; - } - - return CHIP_NO_ERROR; -} - -CHIP_ERROR DeviceEnergyManagementShutdown() -{ - /* Do this in the order Instance first, then delegate - * Ensure we call the Instance->Shutdown to free attribute & command handlers first - */ - if (gDEMInstance) - { - /* deregister attribute & command handlers */ - gDEMInstance->Shutdown(); - gDEMInstance.reset(); - } - if (gDEMDelegate) - { - gDEMDelegate.reset(); - } - return CHIP_NO_ERROR; -} - /* * @brief Creates a Delegate and Instance for EVSE cluster * @@ -147,7 +64,7 @@ CHIP_ERROR DeviceEnergyManagementShutdown() * create the Delegate first, then wrap it in the Instance * Then call the Instance->Init() to register the attribute and command handlers */ -CHIP_ERROR EnergyEvseInit() +CHIP_ERROR EnergyEvseInit(chip::EndpointId endpointId) { CHIP_ERROR err; @@ -174,7 +91,7 @@ CHIP_ERROR EnergyEvseInit() /* Manufacturer may optionally not support all features, commands & attributes */ gEvseInstance = std::make_unique( - EndpointId(ENERGY_EVSE_ENDPOINT), *gEvseDelegate, + EndpointId(endpointId), *gEvseDelegate, BitMask(EnergyEvse::Feature::kChargingPreferences, EnergyEvse::Feature::kRfid), BitMask(EnergyEvse::OptionalAttributes::kSupportsUserMaximumChargingCurrent, EnergyEvse::OptionalAttributes::kSupportsRandomizationWindow, @@ -232,160 +149,6 @@ CHIP_ERROR EnergyEvseShutdown() return CHIP_NO_ERROR; } -/* - * @brief Creates a Delegate and Instance for PowerTopology clusters - * - * The Instance is a container around the Delegate, so - * create the Delegate first, then wrap it in the Instance - * Then call the Instance->Init() to register the attribute and command handlers - */ -CHIP_ERROR PowerTopologyInit() -{ - CHIP_ERROR err; - - if (gPTDelegate || gPTInstance) - { - ChipLogError(AppServer, "PowerTopology Instance or Delegate already exist."); - return CHIP_ERROR_INCORRECT_STATE; - } - - gPTDelegate = std::make_unique(); - if (!gPTDelegate) - { - ChipLogError(AppServer, "Failed to allocate memory for PowerTopology Delegate"); - return CHIP_ERROR_NO_MEMORY; - } - - gPTInstance = - std::make_unique(EndpointId(ENERGY_EVSE_ENDPOINT), *gPTDelegate, - BitMask(PowerTopology::Feature::kNodeTopology), - BitMask(0)); - - if (!gPTInstance) - { - ChipLogError(AppServer, "Failed to allocate memory for PowerTopology Instance"); - gPTDelegate.reset(); - return CHIP_ERROR_NO_MEMORY; - } - - err = gPTInstance->Init(); /* Register Attribute & Command handlers */ - if (err != CHIP_NO_ERROR) - { - ChipLogError(AppServer, "Init failed on gPTInstance"); - gPTInstance.reset(); - gPTDelegate.reset(); - return err; - } - - return CHIP_NO_ERROR; -} - -CHIP_ERROR PowerTopologyShutdown() -{ - /* Do this in the order Instance first, then delegate - * Ensure we call the Instance->Shutdown to free attribute & command handlers first - */ - if (gPTInstance) - { - /* deregister attribute & command handlers */ - gPTInstance->Shutdown(); - gPTInstance.reset(); - } - - if (gPTDelegate) - { - gPTDelegate.reset(); - } - - return CHIP_NO_ERROR; -} - -/* - * @brief Creates a Delegate and Instance for Electrical Power/Energy Measurement clusters - * - * The Instance is a container around the Delegate, so - * create the Delegate first, then wrap it in the Instance - * Then call the Instance->Init() to register the attribute and command handlers - */ -CHIP_ERROR EnergyMeterInit() -{ - CHIP_ERROR err; - - if (gEPMDelegate || gEPMInstance) - { - ChipLogError(AppServer, "EPM Instance or Delegate already exist."); - return CHIP_ERROR_INCORRECT_STATE; - } - - gEPMDelegate = std::make_unique(); - if (!gEPMDelegate) - { - ChipLogError(AppServer, "Failed to allocate memory for EPM Delegate"); - return CHIP_ERROR_NO_MEMORY; - } - - /* Manufacturer may optionally not support all features, commands & attributes */ - /* Turning on all optional features and attributes for test certification purposes */ - gEPMInstance = std::make_unique( - EndpointId(ENERGY_EVSE_ENDPOINT), *gEPMDelegate, - BitMask( - ElectricalPowerMeasurement::Feature::kDirectCurrent, ElectricalPowerMeasurement::Feature::kAlternatingCurrent, - ElectricalPowerMeasurement::Feature::kPolyphasePower, ElectricalPowerMeasurement::Feature::kHarmonics, - ElectricalPowerMeasurement::Feature::kPowerQuality), - BitMask( - ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRanges, - ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeVoltage, - ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeActiveCurrent, - ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeReactiveCurrent, - ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeApparentCurrent, - ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeReactivePower, - ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeApparentPower, - ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRMSVoltage, - ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRMSCurrent, - ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRMSPower, - ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeFrequency, - ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributePowerFactor, - ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeNeutralCurrent)); - - if (!gEPMInstance) - { - ChipLogError(AppServer, "Failed to allocate memory for EPM Instance"); - gEPMDelegate.reset(); - return CHIP_ERROR_NO_MEMORY; - } - - err = gEPMInstance->Init(); /* Register Attribute & Command handlers */ - if (err != CHIP_NO_ERROR) - { - ChipLogError(AppServer, "Init failed on gEPMInstance"); - gEPMInstance.reset(); - gEPMDelegate.reset(); - return err; - } - - return CHIP_NO_ERROR; -} - -CHIP_ERROR EnergyMeterShutdown() -{ - /* Do this in the order Instance first, then delegate - * Ensure we call the Instance->Shutdown to free attribute & command handlers first - */ - if (gEPMInstance) - { - /* deregister attribute & command handlers */ - gEPMInstance->Shutdown(); - gEPMInstance.reset(); - } - - if (gEPMDelegate) - { - gEPMDelegate.reset(); - } - - return CHIP_NO_ERROR; -} - /* * @brief Creates a EVSEManufacturer class to hold the EVSE & DEM clusters * @@ -393,7 +156,9 @@ CHIP_ERROR EnergyMeterShutdown() * create the Delegate first, then wrap it in the Instance * Then call the Instance->Init() to register the attribute and command handlers */ -CHIP_ERROR EVSEManufacturerInit() +CHIP_ERROR EVSEManufacturerInit(chip::EndpointId powerSourceEndpointId, ElectricalPowerMeasurementInstance & epmInstance, + PowerTopologyInstance & ptInstance, DeviceEnergyManagementManager & demInstance, + DeviceEnergyManagementDelegate & demDelegate) { CHIP_ERROR err; @@ -404,18 +169,17 @@ CHIP_ERROR EVSEManufacturerInit() } /* Now create EVSEManufacturer */ - gEvseManufacturer = - std::make_unique(gEvseInstance.get(), gEPMInstance.get(), gPTInstance.get(), gDEMInstance.get()); + gEvseManufacturer = std::make_unique(gEvseInstance.get(), &epmInstance, &ptInstance, &demInstance); if (!gEvseManufacturer) { ChipLogError(AppServer, "Failed to allocate memory for EvseManufacturer"); return CHIP_ERROR_NO_MEMORY; } - gDEMDelegate.get()->SetDEMManufacturerDelegate(*gEvseManufacturer.get()); + demDelegate.SetDEMManufacturerDelegate(*gEvseManufacturer.get()); /* Call Manufacturer specific init */ - err = gEvseManufacturer->Init(); + err = gEvseManufacturer->Init(powerSourceEndpointId); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "Init failed on gEvseManufacturer"); @@ -437,104 +201,3 @@ CHIP_ERROR EVSEManufacturerShutdown() return CHIP_NO_ERROR; } - -void EvseApplicationInit() -{ - if (DeviceEnergyManagementInit() != CHIP_NO_ERROR) - { - return; - } - - if (EnergyEvseInit() != CHIP_NO_ERROR) - { - DeviceEnergyManagementShutdown(); - return; - } - - if (EnergyMeterInit() != CHIP_NO_ERROR) - { - DeviceEnergyManagementShutdown(); - EnergyEvseShutdown(); - return; - } - - if (PowerTopologyInit() != CHIP_NO_ERROR) - { - EVSEManufacturerShutdown(); - DeviceEnergyManagementShutdown(); - EnergyEvseShutdown(); - EnergyMeterShutdown(); - return; - } - - /* Do this last so that the instances for other clusters can be wrapped inside */ - if (EVSEManufacturerInit() != CHIP_NO_ERROR) - { - DeviceEnergyManagementShutdown(); - EnergyEvseShutdown(); - EnergyMeterShutdown(); - return; - } -} - -void EvseApplicationShutdown() -{ - ChipLogDetail(AppServer, "Energy Management App (EVSE): ApplicationShutdown()"); - - /* Shutdown in reverse order that they were created */ - EVSEManufacturerShutdown(); /* Free the EVSEManufacturer */ - PowerTopologyShutdown(); /* Free the PowerTopology */ - EnergyMeterShutdown(); /* Free the Energy Meter */ - EnergyEvseShutdown(); /* Free the EnergyEvse */ - DeviceEnergyManagementShutdown(); /* Free the DEM */ - - Clusters::DeviceEnergyManagementMode::Shutdown(); - Clusters::EnergyEvseMode::Shutdown(); -} - -void emberAfElectricalEnergyMeasurementClusterInitCallback(chip::EndpointId endpointId) -{ - VerifyOrDie(endpointId == 1); // this cluster is only enabled for endpoint 1. - VerifyOrDie(!gEEMAttrAccess); - - gEEMAttrAccess = std::make_unique( - BitMask( - ElectricalEnergyMeasurement::Feature::kImportedEnergy, ElectricalEnergyMeasurement::Feature::kExportedEnergy, - ElectricalEnergyMeasurement::Feature::kCumulativeEnergy, ElectricalEnergyMeasurement::Feature::kPeriodicEnergy), - BitMask( - ElectricalEnergyMeasurement::OptionalAttributes::kOptionalAttributeCumulativeEnergyReset)); - - // Create an accuracy entry which is between +/-0.5 and +/- 5% across the range of all possible energy readings - ElectricalEnergyMeasurement::Structs::MeasurementAccuracyRangeStruct::Type energyAccuracyRanges[] = { - { .rangeMin = 0, - .rangeMax = 1'000'000'000'000'000, // 1 million Mwh - .percentMax = MakeOptional(static_cast(500)), - .percentMin = MakeOptional(static_cast(50)) } - }; - - ElectricalEnergyMeasurement::Structs::MeasurementAccuracyStruct::Type accuracy = { - .measurementType = MeasurementTypeEnum::kElectricalEnergy, - .measured = true, - .minMeasuredValue = 0, - .maxMeasuredValue = 1'000'000'000'000'000, // 1 million Mwh - .accuracyRanges = - DataModel::List(energyAccuracyRanges) - }; - - // Example of setting CumulativeEnergyReset structure - for now set these to 0 - // but the manufacturer may want to store these in non volatile storage for timestamp (based on epoch_s) - ElectricalEnergyMeasurement::Structs::CumulativeEnergyResetStruct::Type resetStruct = { - .importedResetTimestamp = MakeOptional(MakeNullable(static_cast(0))), - .exportedResetTimestamp = MakeOptional(MakeNullable(static_cast(0))), - .importedResetSystime = MakeOptional(MakeNullable(static_cast(0))), - .exportedResetSystime = MakeOptional(MakeNullable(static_cast(0))), - }; - - if (gEEMAttrAccess) - { - gEEMAttrAccess->Init(); - - SetMeasurementAccuracy(endpointId, accuracy); - SetCumulativeReset(endpointId, MakeOptional(resetStruct)); - } -} diff --git a/examples/energy-management-app/energy-management-common/energy-management-app.matter b/examples/energy-management-app/energy-management-common/energy-management-app.matter index a3c2b9f58b5485..bdcbe117c8344b 100644 --- a/examples/energy-management-app/energy-management-common/energy-management-app.matter +++ b/examples/energy-management-app/energy-management-common/energy-management-app.matter @@ -2416,7 +2416,6 @@ endpoint 0 { server cluster AccessControl { callback attribute acl; - callback attribute extension; callback attribute subjectsPerAccessControlEntry; callback attribute targetsPerAccessControlEntry; callback attribute accessControlEntriesPerFabric; @@ -2448,7 +2447,7 @@ endpoint 0 { callback attribute acceptedCommandList; callback attribute attributeList; ram attribute featureMap default = 0; - ram attribute clusterRevision default = 3; + ram attribute clusterRevision default = 4; } server cluster LocalizationConfiguration { @@ -2478,21 +2477,6 @@ endpoint 0 { ram attribute clusterRevision default = 1; } - server cluster PowerSource { - ram attribute status; - ram attribute order; - ram attribute description; - ram attribute wiredCurrentType; - ram attribute wiredNominalVoltage; - ram attribute wiredMaximumCurrent; - callback attribute endpointList; - callback attribute generatedCommandList; - callback attribute acceptedCommandList; - callback attribute attributeList; - ram attribute featureMap default = 0; - ram attribute clusterRevision default = 2; - } - server cluster GeneralCommissioning { ram attribute breadcrumb default = 0x0000000000000000; callback attribute basicCommissioningInfo; @@ -2503,7 +2487,7 @@ endpoint 0 { callback attribute acceptedCommandList; callback attribute attributeList; ram attribute featureMap default = 0; - ram attribute clusterRevision default = 1; + ram attribute clusterRevision default = 2; handle command ArmFailSafe; handle command ArmFailSafeResponse; @@ -2605,8 +2589,10 @@ endpoint 0 { } } endpoint 1 { + device type ma_powersource = 17, version 1; device type ma_electricalsensor = 1296, version 1; device type energy_evse = 1292, version 1; + device type device_energy_management = 1293, version 1; server cluster Identify { @@ -2616,7 +2602,7 @@ endpoint 1 { callback attribute acceptedCommandList; callback attribute attributeList; ram attribute featureMap default = 0; - ram attribute clusterRevision default = 4; + ram attribute clusterRevision default = 5; handle command Identify; handle command TriggerEffect; @@ -2634,6 +2620,21 @@ endpoint 1 { callback attribute clusterRevision; } + server cluster PowerSource { + ram attribute status; + ram attribute order; + ram attribute description; + ram attribute wiredCurrentType; + ram attribute wiredNominalVoltage; + ram attribute wiredMaximumCurrent; + callback attribute endpointList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 3; + } + server cluster ElectricalPowerMeasurement { callback attribute powerMode; callback attribute numberOfMeasurementTypes; @@ -2677,23 +2678,6 @@ endpoint 1 { ram attribute clusterRevision default = 1; } - server cluster WaterHeaterManagement { - callback attribute heaterTypes; - callback attribute heatDemand; - callback attribute tankVolume; - callback attribute estimatedHeatRequired; - callback attribute tankPercentage; - callback attribute boostState; - callback attribute generatedCommandList; - callback attribute acceptedCommandList; - callback attribute attributeList; - callback attribute featureMap; - callback attribute clusterRevision; - - handle command Boost; - handle command CancelBoost; - } - server cluster DeviceEnergyManagement { emits event PowerAdjustStart; emits event PowerAdjustEnd; @@ -2751,7 +2735,7 @@ endpoint 1 { callback attribute acceptedCommandList; callback attribute attributeList; callback attribute featureMap; - ram attribute clusterRevision default = 2; + ram attribute clusterRevision default = 3; handle command GetTargetsResponse; handle command Disable; @@ -2778,12 +2762,137 @@ endpoint 1 { callback attribute acceptedCommandList; callback attribute attributeList; callback attribute featureMap; - ram attribute clusterRevision default = 1; + ram attribute clusterRevision default = 2; handle command ChangeToMode; handle command ChangeToModeResponse; } + server cluster DeviceEnergyManagementMode { + callback attribute supportedModes; + callback attribute currentMode; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 2; + + handle command ChangeToMode; + handle command ChangeToModeResponse; + } +} +endpoint 2 { + device type ma_electricalsensor = 1296, version 1; + device type device_energy_management = 1293, version 1; + device type ma_waterheater = 1295, version 1; + + + server cluster Identify { + ram attribute identifyTime default = 0x0; + ram attribute identifyType default = 0x00; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 5; + + handle command Identify; + } + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster ElectricalPowerMeasurement { + callback attribute powerMode; + callback attribute numberOfMeasurementTypes; + callback attribute accuracy; + callback attribute ranges; + callback attribute voltage; + callback attribute activeCurrent; + callback attribute reactiveCurrent; + callback attribute apparentCurrent; + callback attribute activePower; + callback attribute reactivePower; + callback attribute apparentPower; + callback attribute RMSVoltage; + callback attribute RMSCurrent; + callback attribute RMSPower; + callback attribute frequency; + callback attribute harmonicCurrents; + callback attribute harmonicPhases; + callback attribute powerFactor; + callback attribute neutralCurrent; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 1; + } + + server cluster ElectricalEnergyMeasurement { + callback attribute accuracy; + callback attribute cumulativeEnergyImported; + callback attribute cumulativeEnergyExported; + callback attribute periodicEnergyImported; + callback attribute periodicEnergyExported; + callback attribute cumulativeEnergyReset; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 1; + } + + server cluster WaterHeaterManagement { + callback attribute heaterTypes; + callback attribute heatDemand; + callback attribute tankVolume; + callback attribute estimatedHeatRequired; + callback attribute tankPercentage; + callback attribute boostState; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command Boost; + handle command CancelBoost; + } + + server cluster DeviceEnergyManagement { + callback attribute ESAType; + callback attribute ESACanGenerate; + callback attribute ESAState; + callback attribute absMinPower; + callback attribute absMaxPower; + callback attribute powerAdjustmentCapability; + callback attribute forecast; + callback attribute optOutState; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 4; + } + + server cluster PowerTopology { + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 1; + } + server cluster WaterHeaterMode { callback attribute supportedModes; callback attribute currentMode; @@ -2804,7 +2913,7 @@ endpoint 1 { callback attribute acceptedCommandList; callback attribute attributeList; callback attribute featureMap; - ram attribute clusterRevision default = 1; + ram attribute clusterRevision default = 2; handle command ChangeToMode; handle command ChangeToModeResponse; diff --git a/examples/energy-management-app/energy-management-common/energy-management-app.zap b/examples/energy-management-app/energy-management-common/energy-management-app.zap index 17a539dbf13348..ee365c7ec5c32e 100644 --- a/examples/energy-management-app/energy-management-common/energy-management-app.zap +++ b/examples/energy-management-app/energy-management-common/energy-management-app.zap @@ -1,6 +1,6 @@ { "fileFormat": 2, - "featureLevel": 103, + "featureLevel": 104, "creator": "zap", "keyValuePairs": [ { @@ -41,14 +41,16 @@ "code": 22, "profileId": 259, "label": "MA-rootdevice", - "name": "MA-rootdevice" + "name": "MA-rootdevice", + "deviceTypeOrder": 0 }, "deviceTypes": [ { "code": 22, "profileId": 259, "label": "MA-rootdevice", - "name": "MA-rootdevice" + "name": "MA-rootdevice", + "deviceTypeOrder": 0 } ], "deviceVersions": [ @@ -165,22 +167,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -255,22 +241,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "Extension", - "code": 1, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "SubjectsPerAccessControlEntry", "code": 2, @@ -351,22 +321,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -713,22 +667,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 1, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -771,7 +709,7 @@ "storageOption": "RAM", "singleton": 1, "bounded": 0, - "defaultValue": "3", + "defaultValue": "4", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -851,22 +789,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -973,22 +895,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -1079,22 +985,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -1146,115 +1036,117 @@ ] }, { - "name": "Power Source", - "code": 47, + "name": "General Commissioning", + "code": 48, "mfgCode": null, - "define": "POWER_SOURCE_CLUSTER", + "define": "GENERAL_COMMISSIONING_CLUSTER", "side": "server", "enabled": 1, - "attributes": [ + "commands": [ { - "name": "Status", + "name": "ArmFailSafe", "code": 0, "mfgCode": null, - "side": "server", - "type": "PowerSourceStatusEnum", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 + "source": "client", + "isIncoming": 1, + "isEnabled": 1 }, { - "name": "Order", + "name": "ArmFailSafeResponse", "code": 1, "mfgCode": null, - "side": "server", - "type": "int8u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 + "source": "server", + "isIncoming": 0, + "isEnabled": 1 }, { - "name": "Description", + "name": "SetRegulatoryConfig", "code": 2, "mfgCode": null, - "side": "server", - "type": "char_string", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 + "source": "client", + "isIncoming": 1, + "isEnabled": 1 }, { - "name": "WiredCurrentType", + "name": "SetRegulatoryConfigResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CommissioningComplete", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CommissioningCompleteResponse", "code": 5, "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "Breadcrumb", + "code": 0, + "mfgCode": null, "side": "server", - "type": "WiredCurrentTypeEnum", + "type": "int64u", "included": 1, "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "0x0000000000000000", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "WiredNominalVoltage", - "code": 7, + "name": "BasicCommissioningInfo", + "code": 1, "mfgCode": null, "side": "server", - "type": "int32u", + "type": "BasicCommissioningInfo", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "WiredMaximumCurrent", - "code": 8, + "name": "RegulatoryConfig", + "code": 2, "mfgCode": null, "side": "server", - "type": "int32u", + "type": "RegulatoryLocationTypeEnum", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "EndpointList", - "code": 31, + "name": "LocationCapability", + "code": 3, "mfgCode": null, "side": "server", - "type": "array", + "type": "RegulatoryLocationTypeEnum", "included": 1, "storageOption": "External", "singleton": 0, @@ -1266,11 +1158,11 @@ "reportableChange": 0 }, { - "name": "GeneratedCommandList", - "code": 65528, + "name": "SupportsConcurrentConnection", + "code": 4, "mfgCode": null, "side": "server", - "type": "array", + "type": "boolean", "included": 1, "storageOption": "External", "singleton": 0, @@ -1282,8 +1174,8 @@ "reportableChange": 0 }, { - "name": "AcceptedCommandList", - "code": 65529, + "name": "GeneratedCommandList", + "code": 65528, "mfgCode": null, "side": "server", "type": "array", @@ -1298,8 +1190,8 @@ "reportableChange": 0 }, { - "name": "EventList", - "code": 65530, + "name": "AcceptedCommandList", + "code": 65529, "mfgCode": null, "side": "server", "type": "array", @@ -1364,146 +1256,112 @@ ] }, { - "name": "General Commissioning", - "code": 48, + "name": "Network Commissioning", + "code": 49, "mfgCode": null, - "define": "GENERAL_COMMISSIONING_CLUSTER", + "define": "NETWORK_COMMISSIONING_CLUSTER", "side": "server", "enabled": 1, - "commands": [ + "attributes": [ { - "name": "ArmFailSafe", + "name": "MaxNetworks", "code": 0, "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 }, { - "name": "ArmFailSafeResponse", + "name": "Networks", "code": 1, "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - }, - { - "name": "SetRegulatoryConfig", - "code": 2, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "SetRegulatoryConfigResponse", - "code": 3, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - }, - { - "name": "CommissioningComplete", - "code": 4, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "CommissioningCompleteResponse", - "code": 5, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - } - ], - "attributes": [ - { - "name": "Breadcrumb", - "code": 0, - "mfgCode": null, "side": "server", - "type": "int64u", + "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "0x0000000000000000", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "BasicCommissioningInfo", - "code": 1, + "name": "InterfaceEnabled", + "code": 4, "mfgCode": null, "side": "server", - "type": "BasicCommissioningInfo", + "type": "boolean", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "RegulatoryConfig", - "code": 2, + "name": "LastNetworkingStatus", + "code": 5, "mfgCode": null, "side": "server", - "type": "RegulatoryLocationTypeEnum", + "type": "NetworkCommissioningStatusEnum", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "LocationCapability", - "code": 3, + "name": "LastNetworkID", + "code": 6, "mfgCode": null, "side": "server", - "type": "RegulatoryLocationTypeEnum", + "type": "octet_string", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "SupportsConcurrentConnection", - "code": 4, + "name": "LastConnectErrorValue", + "code": 7, "mfgCode": null, "side": "server", - "type": "boolean", + "type": "int32s", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "GeneratedCommandList", - "code": 65528, + "name": "SupportedWiFiBands", + "code": 8, "mfgCode": null, "side": "server", "type": "array", @@ -1518,8 +1376,8 @@ "reportableChange": 0 }, { - "name": "AcceptedCommandList", - "code": 65529, + "name": "GeneratedCommandList", + "code": 65528, "mfgCode": null, "side": "server", "type": "array", @@ -1534,8 +1392,8 @@ "reportableChange": 0 }, { - "name": "EventList", - "code": 65530, + "name": "AcceptedCommandList", + "code": 65529, "mfgCode": null, "side": "server", "type": "array", @@ -1600,120 +1458,98 @@ ] }, { - "name": "Network Commissioning", - "code": 49, + "name": "General Diagnostics", + "code": 51, "mfgCode": null, - "define": "NETWORK_COMMISSIONING_CLUSTER", + "define": "GENERAL_DIAGNOSTICS_CLUSTER", "side": "server", "enabled": 1, - "attributes": [ + "commands": [ { - "name": "MaxNetworks", + "name": "TestEventTrigger", "code": 0, "mfgCode": null, - "side": "server", - "type": "int8u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 + "source": "client", + "isIncoming": 1, + "isEnabled": 1 }, { - "name": "Networks", + "name": "TimeSnapshot", "code": 1, "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 + "source": "client", + "isIncoming": 1, + "isEnabled": 1 }, { - "name": "InterfaceEnabled", - "code": 4, + "name": "TimeSnapshotResponse", + "code": 2, "mfgCode": null, - "side": "server", - "type": "boolean", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ { - "name": "LastNetworkingStatus", - "code": 5, + "name": "NetworkInterfaces", + "code": 0, "mfgCode": null, "side": "server", - "type": "NetworkCommissioningStatusEnum", + "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "LastNetworkID", - "code": 6, + "name": "RebootCount", + "code": 1, "mfgCode": null, "side": "server", - "type": "octet_string", + "type": "int16u", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "LastConnectErrorValue", - "code": 7, + "name": "UpTime", + "code": 2, "mfgCode": null, "side": "server", - "type": "int32s", + "type": "int64u", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "SupportedWiFiBands", + "name": "TestEventTriggersEnabled", "code": 8, "mfgCode": null, "side": "server", - "type": "array", + "type": "boolean", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -1751,22 +1587,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -1790,10 +1610,10 @@ "side": "server", "type": "bitmap32", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -1806,10 +1626,10 @@ "side": "server", "type": "int16u", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "1", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -1818,15 +1638,15 @@ ] }, { - "name": "General Diagnostics", - "code": 51, + "name": "Administrator Commissioning", + "code": 60, "mfgCode": null, - "define": "GENERAL_DIAGNOSTICS_CLUSTER", + "define": "ADMINISTRATOR_COMMISSIONING_CLUSTER", "side": "server", "enabled": 1, "commands": [ { - "name": "TestEventTrigger", + "name": "OpenCommissioningWindow", "code": 0, "mfgCode": null, "source": "client", @@ -1834,29 +1654,21 @@ "isEnabled": 1 }, { - "name": "TimeSnapshot", - "code": 1, + "name": "RevokeCommissioning", + "code": 2, "mfgCode": null, "source": "client", "isIncoming": 1, "isEnabled": 1 - }, - { - "name": "TimeSnapshotResponse", - "code": 2, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 } ], "attributes": [ { - "name": "NetworkInterfaces", + "name": "WindowStatus", "code": 0, "mfgCode": null, "side": "server", - "type": "array", + "type": "CommissioningWindowStatusEnum", "included": 1, "storageOption": "External", "singleton": 0, @@ -1868,11 +1680,11 @@ "reportableChange": 0 }, { - "name": "RebootCount", + "name": "AdminFabricIndex", "code": 1, "mfgCode": null, "side": "server", - "type": "int16u", + "type": "fabric_idx", "included": 1, "storageOption": "External", "singleton": 0, @@ -1884,11 +1696,11 @@ "reportableChange": 0 }, { - "name": "UpTime", + "name": "AdminVendorId", "code": 2, "mfgCode": null, "side": "server", - "type": "int64u", + "type": "vendor_id", "included": 1, "storageOption": "External", "singleton": 0, @@ -1900,199 +1712,11 @@ "reportableChange": 0 }, { - "name": "TestEventTriggersEnabled", - "code": 8, + "name": "GeneratedCommandList", + "code": 65528, "mfgCode": null, "side": "server", - "type": "boolean", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "GeneratedCommandList", - "code": 65528, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "AcceptedCommandList", - "code": 65529, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "AttributeList", - "code": 65531, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "FeatureMap", - "code": 65532, - "mfgCode": null, - "side": "server", - "type": "bitmap32", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "ClusterRevision", - "code": 65533, - "mfgCode": null, - "side": "server", - "type": "int16u", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - } - ] - }, - { - "name": "Administrator Commissioning", - "code": 60, - "mfgCode": null, - "define": "ADMINISTRATOR_COMMISSIONING_CLUSTER", - "side": "server", - "enabled": 1, - "commands": [ - { - "name": "OpenCommissioningWindow", - "code": 0, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "RevokeCommissioning", - "code": 2, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - } - ], - "attributes": [ - { - "name": "WindowStatus", - "code": 0, - "mfgCode": null, - "side": "server", - "type": "CommissioningWindowStatusEnum", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "AdminFabricIndex", - "code": 1, - "mfgCode": null, - "side": "server", - "type": "fabric_idx", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "AdminVendorId", - "code": 2, - "mfgCode": null, - "side": "server", - "type": "vendor_id", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "GeneratedCommandList", - "code": 65528, - "mfgCode": null, - "side": "server", - "type": "array", + "type": "array", "included": 1, "storageOption": "External", "singleton": 0, @@ -2119,22 +1743,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -2419,22 +2027,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -2639,22 +2231,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -2714,29 +2290,50 @@ "code": 1292, "profileId": 259, "label": "Energy EVSE", - "name": "Energy EVSE" + "name": "Energy EVSE", + "deviceTypeOrder": 0 }, "deviceTypes": [ { "code": 1292, "profileId": 259, "label": "Energy EVSE", - "name": "Energy EVSE" + "name": "Energy EVSE", + "deviceTypeOrder": 0 }, { "code": 1296, "profileId": 259, "label": "MA-electricalsensor", - "name": "MA-electricalsensor" + "name": "MA-electricalsensor", + "deviceTypeOrder": 1 + }, + { + "code": 1293, + "profileId": 259, + "label": "Device Energy Management", + "name": "Device Energy Management", + "deviceTypeOrder": 2 + }, + { + "code": 17, + "profileId": 259, + "label": "MA-powersource", + "name": "MA-powersource", + "deviceTypeOrder": 3 } ], "deviceVersions": [ + 1, + 1, 1, 1 ], "deviceIdentifiers": [ 1292, - 1296 + 1296, + 1293, + 17 ], "deviceTypeName": "Energy EVSE", "deviceTypeCode": 1292, @@ -2832,22 +2429,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -2890,7 +2471,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "4", + "defaultValue": "5", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3003,8 +2584,8 @@ "reportableChange": 0 }, { - "name": "EventList", - "code": 65530, + "name": "AttributeList", + "code": 65531, "mfgCode": null, "side": "server", "type": "array", @@ -3019,8 +2600,194 @@ "reportableChange": 0 }, { - "name": "AttributeList", - "code": 65531, + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Power Source", + "code": 47, + "mfgCode": null, + "define": "POWER_SOURCE_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "Status", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "PowerSourceStatusEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Order", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Description", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "WiredCurrentType", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "WiredCurrentTypeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "WiredNominalVoltage", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "WiredMaximumCurrent", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EndpointList", + "code": 31, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, "mfgCode": null, "side": "server", "type": "array", @@ -3041,10 +2808,10 @@ "side": "server", "type": "bitmap32", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3057,10 +2824,10 @@ "side": "server", "type": "int16u", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "3", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3412,22 +3179,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -3614,22 +3365,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -3697,16 +3432,16 @@ ] }, { - "name": "Water Heater Management", - "code": 148, + "name": "Device Energy Management", + "code": 152, "mfgCode": null, - "define": "WATER_HEATER_MANAGEMENT_CLUSTER", + "define": "DEVICE_ENERGY_MANAGEMENT_CLUSTER", "side": "server", "enabled": 1, "apiMaturity": "provisional", "commands": [ { - "name": "Boost", + "name": "PowerAdjustRequest", "code": 0, "mfgCode": null, "source": "client", @@ -3714,241 +3449,20 @@ "isEnabled": 1 }, { - "name": "CancelBoost", + "name": "CancelPowerAdjustRequest", "code": 1, "mfgCode": null, "source": "client", "isIncoming": 1, "isEnabled": 1 - } - ], - "attributes": [ + }, { - "name": "HeaterTypes", - "code": 0, + "name": "StartTimeAdjustRequest", + "code": 2, "mfgCode": null, - "side": "server", - "type": "WaterHeaterHeatSourceBitmap", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "HeatDemand", - "code": 1, - "mfgCode": null, - "side": "server", - "type": "WaterHeaterHeatSourceBitmap", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "TankVolume", - "code": 2, - "mfgCode": null, - "side": "server", - "type": "int16u", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "EstimatedHeatRequired", - "code": 3, - "mfgCode": null, - "side": "server", - "type": "energy_mwh", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "TankPercentage", - "code": 4, - "mfgCode": null, - "side": "server", - "type": "percent", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "BoostState", - "code": 5, - "mfgCode": null, - "side": "server", - "type": "BoostStateEnum", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "GeneratedCommandList", - "code": 65528, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "AcceptedCommandList", - "code": 65529, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "AttributeList", - "code": 65531, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "FeatureMap", - "code": 65532, - "mfgCode": null, - "side": "server", - "type": "bitmap32", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "ClusterRevision", - "code": 65533, - "mfgCode": null, - "side": "server", - "type": "int16u", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - } - ] - }, - { - "name": "Device Energy Management", - "code": 152, - "mfgCode": null, - "define": "DEVICE_ENERGY_MANAGEMENT_CLUSTER", - "side": "server", - "enabled": 1, - "apiMaturity": "provisional", - "commands": [ - { - "name": "PowerAdjustRequest", - "code": 0, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "CancelPowerAdjustRequest", - "code": 1, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "StartTimeAdjustRequest", - "code": 2, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 + "source": "client", + "isIncoming": 1, + "isEnabled": 1 }, { "name": "PauseRequest", @@ -4152,22 +3666,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -4551,7 +4049,1526 @@ "code": 64, "mfgCode": null, "side": "server", - "type": "int32u", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SessionDuration", + "code": 65, + "mfgCode": null, + "side": "server", + "type": "elapsed_s", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SessionEnergyCharged", + "code": 66, + "mfgCode": null, + "side": "server", + "type": "energy_mwh", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "EVConnected", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "EVNotDetected", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "EnergyTransferStarted", + "code": 2, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "EnergyTransferStopped", + "code": 3, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "Fault", + "code": 4, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "RFID", + "code": 5, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "Power Topology", + "code": 156, + "mfgCode": null, + "define": "POWER_TOPOLOGY_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Energy EVSE Mode", + "code": 157, + "mfgCode": null, + "define": "ENERGY_EVSE_MODE_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ChangeToMode", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ChangeToModeResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "SupportedModes", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentMode", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Device Energy Management Mode", + "code": 159, + "mfgCode": null, + "define": "DEVICE_ENERGY_MANAGEMENT_MODE_CLUSTER", + "side": "server", + "enabled": 1, + "apiMaturity": "provisional", + "commands": [ + { + "name": "ChangeToMode", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ChangeToModeResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "SupportedModes", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentMode", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + } + ] + }, + { + "id": 3, + "name": "Anonymous Endpoint Type", + "deviceTypeRef": { + "code": 1295, + "profileId": 259, + "label": "MA-waterheater", + "name": "MA-waterheater", + "deviceTypeOrder": 0 + }, + "deviceTypes": [ + { + "code": 1295, + "profileId": 259, + "label": "MA-waterheater", + "name": "MA-waterheater", + "deviceTypeOrder": 0 + }, + { + "code": 1296, + "profileId": 259, + "label": "MA-electricalsensor", + "name": "MA-electricalsensor", + "deviceTypeOrder": 1 + }, + { + "code": 1293, + "profileId": 259, + "label": "Device Energy Management", + "name": "Device Energy Management", + "deviceTypeOrder": 2 + } + ], + "deviceVersions": [ + 1, + 1, + 1 + ], + "deviceIdentifiers": [ + 1295, + 1296, + 1293 + ], + "deviceTypeName": "MA-waterheater", + "deviceTypeCode": 1295, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "IdentifyTime", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "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": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "5", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Electrical Power Measurement", + "code": 144, + "mfgCode": null, + "define": "ELECTRICAL_POWER_MEASUREMENT_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "PowerMode", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "PowerModeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NumberOfMeasurementTypes", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Accuracy", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Ranges", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Voltage", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "voltage_mv", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveCurrent", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "amperage_ma", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ReactiveCurrent", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "amperage_ma", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ApparentCurrent", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "amperage_ma", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActivePower", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "power_mw", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ReactivePower", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "power_mw", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ApparentPower", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "power_mw", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RMSVoltage", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "voltage_mv", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RMSCurrent", + "code": 12, + "mfgCode": null, + "side": "server", + "type": "amperage_ma", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RMSPower", + "code": 13, + "mfgCode": null, + "side": "server", + "type": "power_mw", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Frequency", + "code": 14, + "mfgCode": null, + "side": "server", + "type": "int64s", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "HarmonicCurrents", + "code": 15, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "HarmonicPhases", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PowerFactor", + "code": 17, + "mfgCode": null, + "side": "server", + "type": "int64s", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NeutralCurrent", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "amperage_ma", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Electrical Energy Measurement", + "code": 145, + "mfgCode": null, + "define": "ELECTRICAL_ENERGY_MEASUREMENT_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "Accuracy", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "MeasurementAccuracyStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CumulativeEnergyImported", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "EnergyMeasurementStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CumulativeEnergyExported", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "EnergyMeasurementStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PeriodicEnergyImported", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "EnergyMeasurementStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PeriodicEnergyExported", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "EnergyMeasurementStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CumulativeEnergyReset", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "CumulativeEnergyResetStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Water Heater Management", + "code": 148, + "mfgCode": null, + "define": "WATER_HEATER_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "apiMaturity": "provisional", + "commands": [ + { + "name": "Boost", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CancelBoost", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "HeaterTypes", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "WaterHeaterHeatSourceBitmap", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "HeatDemand", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "WaterHeaterHeatSourceBitmap", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TankVolume", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", "included": 1, "storageOption": "External", "singleton": 0, @@ -4563,11 +5580,11 @@ "reportableChange": 0 }, { - "name": "SessionDuration", - "code": 65, + "name": "EstimatedHeatRequired", + "code": 3, "mfgCode": null, "side": "server", - "type": "elapsed_s", + "type": "energy_mwh", "included": 1, "storageOption": "External", "singleton": 0, @@ -4579,11 +5596,11 @@ "reportableChange": 0 }, { - "name": "SessionEnergyCharged", - "code": 66, + "name": "TankPercentage", + "code": 4, "mfgCode": null, "side": "server", - "type": "energy_mwh", + "type": "percent", "included": 1, "storageOption": "External", "singleton": 0, @@ -4595,11 +5612,11 @@ "reportableChange": 0 }, { - "name": "GeneratedCommandList", - "code": 65528, + "name": "BoostState", + "code": 5, "mfgCode": null, "side": "server", - "type": "array", + "type": "BoostStateEnum", "included": 1, "storageOption": "External", "singleton": 0, @@ -4611,8 +5628,8 @@ "reportableChange": 0 }, { - "name": "AcceptedCommandList", - "code": 65529, + "name": "GeneratedCommandList", + "code": 65528, "mfgCode": null, "side": "server", "type": "array", @@ -4627,8 +5644,8 @@ "reportableChange": 0 }, { - "name": "EventList", - "code": 65530, + "name": "AcceptedCommandList", + "code": 65529, "mfgCode": null, "side": "server", "type": "array", @@ -4681,75 +5698,96 @@ "side": "server", "type": "int16u", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "2", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 } - ], - "events": [ + ] + }, + { + "name": "Device Energy Management", + "code": 152, + "mfgCode": null, + "define": "DEVICE_ENERGY_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "apiMaturity": "provisional", + "attributes": [ { - "name": "EVConnected", + "name": "ESAType", "code": 0, "mfgCode": null, "side": "server", - "included": 1 + "type": "ESATypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 }, { - "name": "EVNotDetected", + "name": "ESACanGenerate", "code": 1, "mfgCode": null, "side": "server", - "included": 1 + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 }, { - "name": "EnergyTransferStarted", + "name": "ESAState", "code": 2, "mfgCode": null, "side": "server", - "included": 1 + "type": "ESAStateEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 }, { - "name": "EnergyTransferStopped", + "name": "AbsMinPower", "code": 3, "mfgCode": null, "side": "server", - "included": 1 + "type": "power_mw", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 }, { - "name": "Fault", + "name": "AbsMaxPower", "code": 4, "mfgCode": null, "side": "server", - "included": 1 - }, - { - "name": "RFID", - "code": 5, - "mfgCode": null, - "side": "server", - "included": 1 - } - ] - }, - { - "name": "Power Topology", - "code": 156, - "mfgCode": null, - "define": "POWER_TOPOLOGY_CLUSTER", - "side": "server", - "enabled": 1, - "attributes": [ - { - "name": "GeneratedCommandList", - "code": 65528, - "mfgCode": null, - "side": "server", - "type": "array", + "type": "power_mw", "included": 1, "storageOption": "External", "singleton": 0, @@ -4761,11 +5799,11 @@ "reportableChange": 0 }, { - "name": "AcceptedCommandList", - "code": 65529, + "name": "PowerAdjustmentCapability", + "code": 5, "mfgCode": null, "side": "server", - "type": "array", + "type": "PowerAdjustCapabilityStruct", "included": 1, "storageOption": "External", "singleton": 0, @@ -4777,11 +5815,11 @@ "reportableChange": 0 }, { - "name": "EventList", - "code": 65530, + "name": "Forecast", + "code": 6, "mfgCode": null, "side": "server", - "type": "array", + "type": "ForecastStruct", "included": 1, "storageOption": "External", "singleton": 0, @@ -4793,11 +5831,11 @@ "reportableChange": 0 }, { - "name": "AttributeList", - "code": 65531, + "name": "OptOutState", + "code": 7, "mfgCode": null, "side": "server", - "type": "array", + "type": "OptOutStateEnum", "included": 1, "storageOption": "External", "singleton": 0, @@ -4809,11 +5847,11 @@ "reportableChange": 0 }, { - "name": "FeatureMap", - "code": 65532, + "name": "GeneratedCommandList", + "code": 65528, "mfgCode": null, "side": "server", - "type": "bitmap32", + "type": "array", "included": 1, "storageOption": "External", "singleton": 0, @@ -4825,52 +5863,24 @@ "reportableChange": 0 }, { - "name": "ClusterRevision", - "code": 65533, + "name": "AcceptedCommandList", + "code": 65529, "mfgCode": null, "side": "server", - "type": "int16u", + "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "1", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 - } - ] - }, - { - "name": "Energy EVSE Mode", - "code": 157, - "mfgCode": null, - "define": "ENERGY_EVSE_MODE_CLUSTER", - "side": "server", - "enabled": 1, - "commands": [ - { - "name": "ChangeToMode", - "code": 0, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 }, { - "name": "ChangeToModeResponse", - "code": 1, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - } - ], - "attributes": [ - { - "name": "SupportedModes", - "code": 0, + "name": "AttributeList", + "code": 65531, "mfgCode": null, "side": "server", "type": "array", @@ -4885,11 +5895,11 @@ "reportableChange": 0 }, { - "name": "CurrentMode", - "code": 1, + "name": "FeatureMap", + "code": 65532, "mfgCode": null, "side": "server", - "type": "int8u", + "type": "bitmap32", "included": 1, "storageOption": "External", "singleton": 0, @@ -4901,24 +5911,34 @@ "reportableChange": 0 }, { - "name": "GeneratedCommandList", - "code": 65528, + "name": "ClusterRevision", + "code": 65533, "mfgCode": null, "side": "server", - "type": "array", + "type": "int16u", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "4", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 - }, + } + ] + }, + { + "name": "Power Topology", + "code": 156, + "mfgCode": null, + "define": "POWER_TOPOLOGY_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ { - "name": "AcceptedCommandList", - "code": 65529, + "name": "GeneratedCommandList", + "code": 65528, "mfgCode": null, "side": "server", "type": "array", @@ -4933,8 +5953,8 @@ "reportableChange": 0 }, { - "name": "EventList", - "code": 65530, + "name": "AcceptedCommandList", + "code": 65529, "mfgCode": null, "side": "server", "type": "array", @@ -5088,22 +6108,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -5245,22 +6249,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -5303,7 +6291,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "1", + "defaultValue": "2", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -5330,6 +6318,14 @@ "endpointId": 1, "networkId": 0, "parentEndpointIdentifier": null + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 2, + "profileId": 259, + "endpointId": 2, + "networkId": 0, + "parentEndpointIdentifier": 0 } ] } \ No newline at end of file diff --git a/examples/energy-management-app/energy-management-common/water-heater/include/WaterHeaterMain.h b/examples/energy-management-app/energy-management-common/energy-reporting/include/ElectricalSensorInit.h similarity index 55% rename from examples/energy-management-app/energy-management-common/water-heater/include/WaterHeaterMain.h rename to examples/energy-management-app/energy-management-common/energy-reporting/include/ElectricalSensorInit.h index 819ff9e4d160ca..6e0c38bb7d85bb 100644 --- a/examples/energy-management-app/energy-management-common/water-heater/include/WaterHeaterMain.h +++ b/examples/energy-management-app/energy-management-common/energy-reporting/include/ElectricalSensorInit.h @@ -18,15 +18,16 @@ #pragma once -namespace chip { -namespace app { -namespace Clusters { -namespace WaterHeaterManagement { +#include +#include +#include +#include -void FullWhmApplicationInit(); -void FullWhmApplicationShutdown(); +chip::app::Clusters::PowerTopology::PowerTopologyInstance * GetPTInstance(); +chip::app::Clusters::ElectricalPowerMeasurement::ElectricalPowerMeasurementInstance * GetEPMInstance(); -} // namespace WaterHeaterManagement -} // namespace Clusters -} // namespace app -} // namespace chip +CHIP_ERROR PowerTopologyInit(chip::EndpointId endpointId); +CHIP_ERROR PowerTopologyShutdown(); + +CHIP_ERROR ElectricalPowerMeasurementInit(chip::EndpointId endpointId); +CHIP_ERROR ElectricalPowerMeasurementShutdown(); diff --git a/examples/energy-management-app/energy-management-common/energy-reporting/src/FakeReadings.cpp b/examples/energy-management-app/energy-management-common/energy-reporting/src/FakeReadings.cpp index bffe3c900d29af..8fab0e2a7dbe07 100644 --- a/examples/energy-management-app/energy-management-common/energy-reporting/src/FakeReadings.cpp +++ b/examples/energy-management-app/energy-management-common/energy-reporting/src/FakeReadings.cpp @@ -16,8 +16,8 @@ * limitations under the License. */ -#include #include +#include #include #include diff --git a/examples/energy-management-app/energy-management-common/water-heater/include/WhmMain.h b/examples/energy-management-app/energy-management-common/water-heater/include/WhmMain.h index 34f04d8cbb6b8f..d0fa8d97f5cc14 100644 --- a/examples/energy-management-app/energy-management-common/water-heater/include/WhmMain.h +++ b/examples/energy-management-app/energy-management-common/water-heater/include/WhmMain.h @@ -25,7 +25,7 @@ namespace app { namespace Clusters { namespace WaterHeaterManagement { -CHIP_ERROR WhmApplicationInit(); +CHIP_ERROR WhmApplicationInit(EndpointId endpointId); CHIP_ERROR WhmApplicationShutdown(); } // namespace WaterHeaterManagement diff --git a/examples/energy-management-app/energy-management-common/water-heater/src/WaterHeaterMain.cpp b/examples/energy-management-app/energy-management-common/water-heater/src/WaterHeaterMain.cpp deleted file mode 100644 index 0c8e44ac7cb248..00000000000000 --- a/examples/energy-management-app/energy-management-common/water-heater/src/WaterHeaterMain.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * - * 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. - */ - -#include "EnergyManagementAppCmdLineOptions.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace chip { -namespace app { -namespace Clusters { -namespace WaterHeaterManagement { - -void FullWhmApplicationInit() -{ - ReturnOnFailure(WhmApplicationInit()); - - if (DeviceEnergyManagementInit() != CHIP_NO_ERROR) - { - WhmApplicationShutdown(); - return; - } - - if (EnergyMeterInit() != CHIP_NO_ERROR) - { - DeviceEnergyManagementShutdown(); - WhmApplicationShutdown(); - return; - } - - if (PowerTopologyInit() != CHIP_NO_ERROR) - { - EnergyMeterShutdown(); - DeviceEnergyManagementShutdown(); - WhmApplicationShutdown(); - return; - } - - /* For Device Energy Management we need the ESA to be Online and ready to accept commands */ - - GetDEMDelegate()->SetESAState(ESAStateEnum::kOnline); - GetDEMDelegate()->SetESAType(ESATypeEnum::kWaterHeating); - GetDEMDelegate()->SetDEMManufacturerDelegate(*GetWhmManufacturer()); - - // Set the abs min and max power - GetDEMDelegate()->SetAbsMinPower(1200000); // 1.2KW - GetDEMDelegate()->SetAbsMaxPower(7600000); // 7.6KW -} - -void FullWhmApplicationShutdown() -{ - ChipLogDetail(AppServer, "Energy Management App (WaterHeater): ApplicationShutdown()"); - - /* Shutdown in reverse order that they were created */ - PowerTopologyShutdown(); /* Free the PowerTopology */ - EnergyMeterShutdown(); /* Free the Energy Meter */ - DeviceEnergyManagementShutdown(); /* Free the DEM */ - WhmApplicationShutdown(); - - Clusters::DeviceEnergyManagementMode::Shutdown(); - Clusters::WaterHeaterMode::Shutdown(); -} - -} // namespace WaterHeaterManagement -} // namespace Clusters -} // namespace app -} // namespace chip diff --git a/examples/energy-management-app/energy-management-common/water-heater/src/WhmDelegateImpl.cpp b/examples/energy-management-app/energy-management-common/water-heater/src/WhmDelegateImpl.cpp index 79a64d5226f486..edab8b7cd15790 100644 --- a/examples/energy-management-app/energy-management-common/water-heater/src/WhmDelegateImpl.cpp +++ b/examples/energy-management-app/energy-management-common/water-heater/src/WhmDelegateImpl.cpp @@ -307,6 +307,7 @@ int16_t WaterHeaterManagementDelegate::GetActiveTargetWaterTemperature() const // Note, in practise the actual heating is likely to be controlled by the thermostat's occupiedHeatingSetpoint most of the // time, and the TemporarySetpoint (if not null) would be overiding the thermostat's occupiedHeatingSetpoint. // However, this code doesn't rely upon the thermostat cluster. + // TODO: Implement Thermostat Cluster temperature handling. It's mandatory to be spec conformant. int16_t targetTemperature = (mBoostState == BoostStateEnum::kActive && mBoostTemporarySetpoint.HasValue()) ? mBoostTemporarySetpoint.Value() : mTargetWaterTemperature; diff --git a/examples/energy-management-app/energy-management-common/water-heater/src/WhmMain.cpp b/examples/energy-management-app/energy-management-common/water-heater/src/WhmMain.cpp index 038e332bd31aff..b53da3c7d69251 100644 --- a/examples/energy-management-app/energy-management-common/water-heater/src/WhmMain.cpp +++ b/examples/energy-management-app/energy-management-common/water-heater/src/WhmMain.cpp @@ -24,8 +24,6 @@ #include #include -static constexpr int WHM_ENDPOINT = 1; - using namespace chip; using namespace chip::app; using namespace chip::app::DataModel; @@ -53,7 +51,7 @@ WhmManufacturer * GetWhmManufacturer() * create the Delegate first, then wrap it in the Instance * Then call the Instance->Init() to register the attribute and command handlers */ -CHIP_ERROR WhmInit() +CHIP_ERROR WhmInit(EndpointId endpointId) { CHIP_ERROR err; @@ -63,7 +61,7 @@ CHIP_ERROR WhmInit() return CHIP_ERROR_INCORRECT_STATE; } - gWhmDelegate = std::make_unique(WHM_ENDPOINT); + gWhmDelegate = std::make_unique(endpointId); if (!gWhmDelegate) { ChipLogError(AppServer, "Failed to allocate memory for WaterHeaterManagementDelegate"); @@ -72,7 +70,7 @@ CHIP_ERROR WhmInit() /* Manufacturer may optionally not support all features, commands & attributes */ gWhmInstance = std::make_unique( - EndpointId(WHM_ENDPOINT), *gWhmDelegate, BitMask(Feature::kEnergyManagement, Feature::kTankPercent)); + EndpointId(endpointId), *gWhmDelegate, BitMask(Feature::kEnergyManagement, Feature::kTankPercent)); if (!gWhmInstance) { ChipLogError(AppServer, "Failed to allocate memory for WaterHeaterManagementInstance"); @@ -167,9 +165,9 @@ CHIP_ERROR WhmManufacturerShutdown() return CHIP_NO_ERROR; } -CHIP_ERROR WhmApplicationInit() +CHIP_ERROR WhmApplicationInit(EndpointId endpointId) { - ReturnErrorOnFailure(WhmInit()); + ReturnErrorOnFailure(WhmInit(endpointId)); /* Do this last so that the instances for other clusters can be wrapped inside */ ReturnErrorOnFailure(WhmManufacturerInit()); diff --git a/examples/energy-management-app/energy-management-common/water-heater/src/water-heater-mode.cpp b/examples/energy-management-app/energy-management-common/water-heater/src/water-heater-mode.cpp index 9c4121fb70d668..76f61b72b97fd8 100755 --- a/examples/energy-management-app/energy-management-common/water-heater/src/water-heater-mode.cpp +++ b/examples/energy-management-app/energy-management-common/water-heater/src/water-heater-mode.cpp @@ -24,9 +24,12 @@ using chip::Protocols::InteractionModel::Status; template using List = chip::app::DataModel::List; using ModeTagStructType = chip::app::Clusters::detail::Structs::ModeTagStruct::Type; +namespace { -static ExampleWaterHeaterModeDelegate * gWaterHeaterModeDelegate = nullptr; -static ModeBase::Instance * gWaterHeaterModeInstance = nullptr; +ExampleWaterHeaterModeDelegate * gWaterHeaterModeDelegate = nullptr; +ModeBase::Instance * gWaterHeaterModeInstance = nullptr; + +} // namespace CHIP_ERROR ExampleWaterHeaterModeDelegate::Init() { @@ -99,7 +102,6 @@ void emberAfWaterHeaterModeClusterInitCallback(chip::EndpointId endpointId) { VerifyOrDie(gWaterHeaterModeDelegate == nullptr && gWaterHeaterModeInstance == nullptr); gWaterHeaterModeDelegate = new WaterHeaterMode::ExampleWaterHeaterModeDelegate; - gWaterHeaterModeInstance = - new ModeBase::Instance(gWaterHeaterModeDelegate, endpointId, WaterHeaterMode::Id, chip::to_underlying(Feature::kOnOff)); + gWaterHeaterModeInstance = new ModeBase::Instance(gWaterHeaterModeDelegate, endpointId, WaterHeaterMode::Id, 0); gWaterHeaterModeInstance->Init(); } diff --git a/examples/energy-management-app/esp32/main/main.cpp b/examples/energy-management-app/esp32/main/main.cpp index d235fa4291ac98..9e1dff9b43b745 100644 --- a/examples/energy-management-app/esp32/main/main.cpp +++ b/examples/energy-management-app/esp32/main/main.cpp @@ -17,15 +17,8 @@ #include "DeviceCallbacks.h" -#if CONFIG_ENABLE_EXAMPLE_EVSE_DEVICE -#include -#endif // CONFIG_ENABLE_EXAMPLE_EVSE_DEVICE - -#if CONFIG_ENABLE_EXAMPLE_WATER_HEATER_DEVICE -#include -#endif // CONFIG_ENABLE_EXAMPLE_EVSE_DEVICE - #include "esp_log.h" +#include #include #include #include @@ -43,8 +36,10 @@ #include "nvs_flash.h" #include "shell_extension/launch.h" #include "shell_extension/openthread_cli_register.h" +#include #include #include +#include #include #include #include @@ -80,6 +75,7 @@ using namespace ::chip::Credentials; using namespace ::chip::DeviceManager; using namespace ::chip::DeviceLayer; using namespace chip::app::Clusters::WaterHeaterManagement; +using namespace chip::app::Clusters::DeviceEnergyManagement; #if CONFIG_ENABLE_ESP_INSIGHTS_TRACE extern const char insights_auth_key_start[] asm("_binary_insights_auth_key_txt_start"); @@ -92,6 +88,10 @@ static AppDeviceCallbacks EchoCallbacks; static DeviceCallbacksDelegate sAppDeviceCallbacksDelegate; namespace { + +constexpr chip::EndpointId kEvseEndpoint = 1; +constexpr chip::EndpointId kWaterHeaterEndpoint = 2; + #if CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER DeviceLayer::ESP32FactoryDataProvider sFactoryDataProvider; #endif // CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER @@ -156,15 +156,29 @@ chip::BitMask GetFeatureMapFromCmdLine() #error Cannot define CONFIG_ENABLE_EXAMPLE_EVSE_DEVICE and CONFIG_ENABLE_EXAMPLE_WATER_HEATER_DEVICE #endif +EndpointId GetEnergyDeviceEndpointId() +{ +#if defined(CONFIG_ENABLE_EXAMPLE_WATER_HEATER_DEVICE) + return kWaterHeaterEndpoint; +#else + return kEvseEndpoint; +#endif +} + void ApplicationInit() { ESP_LOGD(TAG, "Energy Management App: ApplicationInit()"); #if CONFIG_ENABLE_EXAMPLE_EVSE_DEVICE + EvseApplicationInit(); + // Disable Water Heater Endpoint + emberAfEndpointEnableDisable(kWaterHeaterEndpoint, false); #endif // CONFIG_ENABLE_EXAMPLE_EVSE_DEVICE #if CONFIG_ENABLE_EXAMPLE_WATER_HEATER_DEVICE - FullWhmApplicationInit(); + WaterHeaterApplicationInit(); + // Disable EVSE Endpoint + emberAfEndpointEnableDisable(kEvseEndpoint, false); #endif // CONFIG_ENABLE_EXAMPLE_WATER_HEATER_DEVICE } @@ -177,7 +191,7 @@ void ApplicationShutdown() #endif // CONFIG_ENABLE_EXAMPLE_EVSE_DEVICE #if CONFIG_ENABLE_EXAMPLE_WATER_HEATER_DEVICE - FullWhmApplicationShutdown(); + WaterHeaterApplicationShutdown(); #endif // CONFIG_ENABLE_EXAMPLE_WATER_HEATER_DEVICE } diff --git a/examples/energy-management-app/linux/BUILD.gn b/examples/energy-management-app/linux/BUILD.gn index a9d41a1e76d033..e742c05d692296 100644 --- a/examples/energy-management-app/linux/BUILD.gn +++ b/examples/energy-management-app/linux/BUILD.gn @@ -34,6 +34,7 @@ config("includes") { executable("chip-energy-management-app") { sources = [ + "${chip_root}/examples/energy-management-app/energy-management-common/common/src/EnergyManagementAppCommonMain.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/common/src/EnergyTimeUtils.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/device-energy-management/src/DEMTestEventTriggers.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/device-energy-management/src/DeviceEnergyManagementDelegateImpl.cpp", @@ -51,7 +52,6 @@ executable("chip-energy-management-app") { "${chip_root}/examples/energy-management-app/energy-management-common/energy-reporting/src/EnergyReportingEventTriggers.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/energy-reporting/src/FakeReadings.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/energy-reporting/src/PowerTopologyDelegate.cpp", - "${chip_root}/examples/energy-management-app/energy-management-common/water-heater/src/WaterHeaterMain.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/water-heater/src/WhmDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/water-heater/src/WhmInstance.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/water-heater/src/WhmMain.cpp", diff --git a/examples/energy-management-app/linux/main.cpp b/examples/energy-management-app/linux/main.cpp index 7a6312538ada45..d4cefde1c14ace 100644 --- a/examples/energy-management-app/linux/main.cpp +++ b/examples/energy-management-app/linux/main.cpp @@ -17,9 +17,10 @@ */ #include -#include -#include +#include +#include #include +#include #include using namespace chip; @@ -39,10 +40,12 @@ static bool EnergyAppOptionHandler(const char * aProgram, chip::ArgParser::Optio constexpr uint16_t kOptionApplication = 0xffd0; constexpr uint16_t kOptionFeatureMap = 0xffd1; -constexpr const char * kEvseApp = "evse"; -constexpr const char * kWhmApp = "water-heater"; - -constexpr const char * kValidApps[] = { kEvseApp, kWhmApp }; +constexpr chip::EndpointId kEvseEndpoint = 1; +constexpr chip::EndpointId kWaterHeaterEndpoint = 2; +constexpr const char * kEvseApp = "evse"; +constexpr const char * kWhmApp = "water-heater"; +constexpr const char * kValidApps[] = { kEvseApp, kWhmApp }; +constexpr EndpointId kValidEndpoints[] = { kEvseEndpoint, kWaterHeaterEndpoint }; // Define the chip::ArgParser command line structures for extending the command line to support the // energy apps @@ -65,11 +68,12 @@ namespace DeviceEnergyManagement { // Keep track of the parsed featureMap option static chip::BitMask sFeatureMap(Feature::kPowerAdjustment, Feature::kPowerForecastReporting, - Feature::kStateForecastReporting, Feature::kStartTimeAdjustment, Feature::kPausable, - Feature::kForecastAdjustment, Feature::kConstraintBasedAdjustment); + Feature::kStartTimeAdjustment, Feature::kPausable, Feature::kForecastAdjustment, + Feature::kConstraintBasedAdjustment); // Make EVSE the default app -static const char * spApp = kEvseApp; +static const char * spApp = kEvseApp; +static EndpointId sAppEndpointId = kEvseEndpoint; chip::BitMask GetFeatureMapFromCmdLine() { @@ -81,6 +85,11 @@ chip::BitMask GetFeatureMapFromCmdLine() } // namespace app } // namespace chip +chip::EndpointId GetEnergyDeviceEndpointId() +{ + return sAppEndpointId; +} + static uint32_t ParseNumber(const char * pString) { uint32_t num = 0; @@ -101,11 +110,15 @@ void ApplicationInit() ChipLogDetail(AppServer, "Energy Management App: ApplicationInit()"); if (strcmp(spApp, kEvseApp) == 0) { + // Disable Water Heater Endpoint + emberAfEndpointEnableDisable(kWaterHeaterEndpoint, false); EvseApplicationInit(); } else if (strcmp(spApp, kWhmApp) == 0) { - FullWhmApplicationInit(); + // Disable EVSE Endpoint + emberAfEndpointEnableDisable(kEvseEndpoint, false); + WaterHeaterApplicationInit(); } else { @@ -118,7 +131,7 @@ void ApplicationShutdown() ChipLogDetail(AppServer, "Energy Management App: ApplicationShutdown()"); EvseApplicationShutdown(); - FullWhmApplicationShutdown(); + WaterHeaterApplicationShutdown(); } static bool EnergyAppOptionHandler(const char * aProgram, chip::ArgParser::OptionSet * aOptions, int aIdentifier, @@ -134,7 +147,8 @@ static bool EnergyAppOptionHandler(const char * aProgram, chip::ArgParser::Optio { if (strcmp(kValidApps[idx], aValue) == 0) { - spApp = kValidApps[idx]; + spApp = kValidApps[idx]; + sAppEndpointId = kValidEndpoints[idx]; break; } } diff --git a/examples/energy-management-app/silabs/BUILD.gn b/examples/energy-management-app/silabs/BUILD.gn index d4a4887ceec3a7..1ed8a4473bd0d6 100644 --- a/examples/energy-management-app/silabs/BUILD.gn +++ b/examples/energy-management-app/silabs/BUILD.gn @@ -166,6 +166,7 @@ silabs_executable("energy-management-app") { } sources = [ + "${chip_root}/examples/energy-management-app/energy-management-common/common/src/EnergyManagementAppCommonMain.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/common/src/EnergyTimeUtils.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/device-energy-management/src/DEMTestEventTriggers.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/device-energy-management/src/DeviceEnergyManagementDelegateImpl.cpp", @@ -183,7 +184,6 @@ silabs_executable("energy-management-app") { "${chip_root}/examples/energy-management-app/energy-management-common/energy-reporting/src/EnergyReportingEventTriggers.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/energy-reporting/src/FakeReadings.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/energy-reporting/src/PowerTopologyDelegate.cpp", - "${chip_root}/examples/energy-management-app/energy-management-common/water-heater/src/WaterHeaterMain.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/water-heater/src/WhmDelegateImpl.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/water-heater/src/WhmInstance.cpp", "${chip_root}/examples/energy-management-app/energy-management-common/water-heater/src/WhmMain.cpp", diff --git a/examples/energy-management-app/silabs/src/AppTask.cpp b/examples/energy-management-app/silabs/src/AppTask.cpp index 42069a85b5de84..f90952ea456f65 100644 --- a/examples/energy-management-app/silabs/src/AppTask.cpp +++ b/examples/energy-management-app/silabs/src/AppTask.cpp @@ -21,12 +21,7 @@ #include "AppConfig.h" #include "AppEvent.h" #include "LEDWidget.h" -#if SL_MATTER_CONFIG_ENABLE_EXAMPLE_EVSE_DEVICE -#include -#endif -#if SL_CONFIG_ENABLE_EXAMPLE_WATER_HEATER_DEVICE -#include -#endif +#include #include #include #include @@ -36,6 +31,7 @@ #include #include #include +#include #include #include @@ -46,6 +42,7 @@ #include +#include #include #ifdef SL_MATTER_TEST_EVENT_TRIGGER_ENABLED @@ -76,8 +73,12 @@ #define APP_EVSE_SWITCH 1 namespace { + LEDWidget sEnergyManagementLED; -} +constexpr chip::EndpointId kEvseEndpoint = 1; +constexpr chip::EndpointId kWaterHeaterEndpoint = 2; + +} // namespace using namespace chip; using namespace chip::app; @@ -130,6 +131,15 @@ chip::BitMask GetFeatureMapFromCmdLine() AppTask AppTask::sAppTask; +EndpointId GetEnergyDeviceEndpointId() +{ +#if defined(SL_CONFIG_ENABLE_EXAMPLE_WATER_HEATER_DEVICE) + return kWaterHeaterEndpoint; +#else + return kEvseEndpoint; +#endif +} + void ApplicationInit() { chip::DeviceLayer::PlatformMgr().LockChipStack(); @@ -138,12 +148,16 @@ void ApplicationInit() SILABS_LOG("energy-management-example EVSE starting. featureMap 0x%08lx", DeviceEnergyManagement::sFeatureMap.Raw()); EvseApplicationInit(); + // Disable Water Heater Endpoint + emberAfEndpointEnableDisable(kWaterHeaterEndpoint, false); #endif // CONFIG_ENABLE_EXAMPLE_EVSE_DEVICE #if SL_CONFIG_ENABLE_EXAMPLE_WATER_HEATER_DEVICE SILABS_LOG("energy-management-example WaterHeater starting. featureMap 0x%08lx", DeviceEnergyManagement::sFeatureMap.Raw()); - FullWhmApplicationInit(); + WaterHeaterApplicationInit(); + // Disable EVSE Endpoint + emberAfEndpointEnableDisable(kEvseEndpoint, false); #endif // CONFIG_ENABLE_EXAMPLE_WATER_HEATER_DEVICE SILABS_LOG("=================================================="); @@ -158,7 +172,7 @@ void ApplicationShutdown() #endif // CONFIG_ENABLE_EXAMPLE_EVSE_DEVICE #if SL_CONFIG_ENABLE_EXAMPLE_WATER_HEATER_DEVICE - FullWhmApplicationShutdown(); + WaterHeaterApplicationShutdown(); #endif // CONFIG_ENABLE_EXAMPLE_WATER_HEATER_DEVICE chip::DeviceLayer::PlatformMgr().UnlockChipStack(); } diff --git a/src/python_testing/TC_EWATERHTR_2_1.py b/src/python_testing/TC_EWATERHTR_2_1.py index 82c9e93dad0414..c0eeaaea3d19a2 100644 --- a/src/python_testing/TC_EWATERHTR_2_1.py +++ b/src/python_testing/TC_EWATERHTR_2_1.py @@ -35,7 +35,7 @@ # --discriminator 1234 # --passcode 20202021 # --hex-arg enableKey:000102030405060708090a0b0c0d0e0f -# --endpoint 1 +# --endpoint 2 # --trace-to json:${TRACE_TEST_JSON}.json # --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto # factory-reset: true diff --git a/src/python_testing/TC_EWATERHTR_2_2.py b/src/python_testing/TC_EWATERHTR_2_2.py index 2c639a7c710d69..91ef5244597a70 100644 --- a/src/python_testing/TC_EWATERHTR_2_2.py +++ b/src/python_testing/TC_EWATERHTR_2_2.py @@ -35,7 +35,7 @@ # --discriminator 1234 # --passcode 20202021 # --hex-arg enableKey:000102030405060708090a0b0c0d0e0f -# --endpoint 1 +# --endpoint 2 # --trace-to json:${TRACE_TEST_JSON}.json # --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto # factory-reset: true diff --git a/src/python_testing/TC_EWATERHTR_2_3.py b/src/python_testing/TC_EWATERHTR_2_3.py index 8833a3c58a223d..ff84a0ffbf363c 100644 --- a/src/python_testing/TC_EWATERHTR_2_3.py +++ b/src/python_testing/TC_EWATERHTR_2_3.py @@ -34,7 +34,7 @@ # --discriminator 1234 # --passcode 20202021 # --hex-arg enableKey:000102030405060708090a0b0c0d0e0f -# --endpoint 1 +# --endpoint 2 # --trace-to json:${TRACE_TEST_JSON}.json # --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto # factory-reset: true diff --git a/src/python_testing/TC_WHM_1_2.py b/src/python_testing/TC_WHM_1_2.py index 0ce34ee83119be..302c53dffc467e 100644 --- a/src/python_testing/TC_WHM_1_2.py +++ b/src/python_testing/TC_WHM_1_2.py @@ -31,7 +31,7 @@ # --discriminator 1234 # --passcode 20202021 # --hex-arg enableKey:000102030405060708090a0b0c0d0e0f -# --endpoint 1 +# --endpoint 2 # --trace-to json:${TRACE_TEST_JSON}.json # --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto # factory-reset: true diff --git a/src/python_testing/TC_WHM_2_1.py b/src/python_testing/TC_WHM_2_1.py index 7380c7a862aa80..13f4c189577ea1 100644 --- a/src/python_testing/TC_WHM_2_1.py +++ b/src/python_testing/TC_WHM_2_1.py @@ -32,7 +32,7 @@ # --commissioning-method on-network # --discriminator 1234 # --passcode 20202021 -# --endpoint 1 +# --endpoint 2 # --trace-to json:${TRACE_TEST_JSON}.json # --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto # factory-reset: true From 29c264723be6ebfb1564d5f999f96e2f70cbc1e0 Mon Sep 17 00:00:00 2001 From: Mathieu Kardous <84793247+mkardous-silabs@users.noreply.github.com> Date: Wed, 27 Nov 2024 19:33:42 -0500 Subject: [PATCH 13/26] [Silabs] General updates and fixes for the Silabs Wi-Fi platforms (#36628) * [SL-UP] Remove two algo design for the wifi retry mechanism (#103) * [SL-UP] Rename ot interval to transport interval (#108) * [SL-UP] Delete unnecessary double abstraction for the wiseconnect power save functions (#109) * [SL-UP] Update spi-multiplex header inclusion (#110) * [SL-UP] Fix Builds after Wi-Fi interface refactor (#111) * [SL-UP] Remove WF200 define duplication to avoid value conflicts at runtime (#126) * fix spacing * restyle * Fix define name * add missing function * Fix wf200 ICD build * Restyled by clang-format * Add debug config * Re added sem check --------- Co-authored-by: Restyled.io --- .../light-switch-app/silabs/openthread.gni | 4 +- examples/lit-icd-app/silabs/openthread.gni | 4 +- examples/lock-app/silabs/openthread.gni | 4 +- .../efr32/project_include/OpenThreadConfig.h | 2 +- examples/platform/silabs/uart.cpp | 2 +- .../silabs/src/RefrigeratorUI.cpp | 6 +- .../smoke-co-alarm-app/silabs/openthread.gni | 4 +- .../thermostat/silabs/src/ThermostatUI.cpp | 6 +- examples/window-app/silabs/openthread.gni | 4 +- .../silabs/CHIPDevicePlatformConfig.h | 4 +- .../silabs/SiWx917/SiWxPlatformInterface.h | 7 +++ .../silabs/multi-ota/OTACustomProcessor.cpp | 7 ++- .../silabs/multi-ota/OTAFirmwareProcessor.cpp | 7 ++- .../multi-ota/OTAMultiImageProcessorImpl.cpp | 7 ++- src/platform/silabs/wifi/BUILD.gn | 13 ++++- .../silabs/wifi/SiWx/WifiInterface.cpp | 54 ++++++----------- .../silabs/wifi/WifiInterfaceAbstraction.cpp | 58 +++++-------------- .../silabs/wifi/WifiInterfaceAbstraction.h | 14 ----- .../silabs/wifi/lwip-support/ethernetif.cpp | 22 +++---- .../silabs/wifi/rs911x/WifiInterface.cpp | 55 +++++++----------- .../silabs/wifi/wf200/WifiInterface.cpp | 17 ++---- .../silabs/wifi/wf200/platform/efr_spi.c | 2 - .../silabs/wifi/wf200/platform/sl_wfx_host.h | 3 + .../silabs/wifi/wf200/platform/wf200_init.c | 1 + src/platform/silabs/wifi/wf200/wf200.gni | 1 - src/platform/silabs/wifi/wfx_msgs.h | 9 +++ third_party/silabs/efr32_sdk.gni | 24 ++------ 27 files changed, 132 insertions(+), 209 deletions(-) diff --git a/examples/light-switch-app/silabs/openthread.gni b/examples/light-switch-app/silabs/openthread.gni index 4ec1c04a927404..88dcdef98ebd06 100644 --- a/examples/light-switch-app/silabs/openthread.gni +++ b/examples/light-switch-app/silabs/openthread.gni @@ -36,8 +36,8 @@ chip_subscription_timeout_resumption = false sl_use_subscription_syncing = true # Openthread Configuration flags -sl_ot_idle_interval_ms = 2100000 # 35 minutes Idle Intervals -sl_ot_active_interval_ms = 1000 # 1000ms Active Intervals +sl_transport_idle_interval_ms = 2100000 # 35 minutes Idle Intervals +sl_transport_active_interval_ms = 1000 # 1000ms Active Intervals # ICD Matter Configuration flags sl_idle_mode_duration_s = 1800 # 30min Idle Mode Duration diff --git a/examples/lit-icd-app/silabs/openthread.gni b/examples/lit-icd-app/silabs/openthread.gni index c09176354a3d76..9f38cd9136ba5f 100644 --- a/examples/lit-icd-app/silabs/openthread.gni +++ b/examples/lit-icd-app/silabs/openthread.gni @@ -37,8 +37,8 @@ chip_enable_icd_lit = true chip_enable_icd_dsls = true # Openthread Configuration flags -sl_ot_idle_interval_ms = 3600000 # 60mins Idle Polling Interval -sl_ot_active_interval_ms = 1000 # 1000ms Active Polling Interval +sl_transport_idle_interval_ms = 3600000 # 60mins Idle Polling Interval +sl_transport_active_interval_ms = 1000 # 1000ms Active Polling Interval # ICD Matter Configuration flags sl_idle_mode_duration_s = 3600 # 60min Idle Mode Duration diff --git a/examples/lock-app/silabs/openthread.gni b/examples/lock-app/silabs/openthread.gni index 46359c13e89276..f9b6888d597afd 100644 --- a/examples/lock-app/silabs/openthread.gni +++ b/examples/lock-app/silabs/openthread.gni @@ -33,8 +33,8 @@ chip_subscription_timeout_resumption = false sl_use_subscription_syncing = true # Openthread Configuration flags -sl_ot_idle_interval_ms = 5000 # 5s Idle Intervals -sl_ot_active_interval_ms = 500 # 500ms Active Intervals +sl_transport_idle_interval_ms = 5000 # 5s Idle Intervals +sl_transport_active_interval_ms = 500 # 500ms Active Intervals # ICD Matter Configuration flags sl_idle_mode_duration_s = 600 # 10min Idle Mode Duration diff --git a/examples/platform/silabs/efr32/project_include/OpenThreadConfig.h b/examples/platform/silabs/efr32/project_include/OpenThreadConfig.h index ed56c7a5785d8a..c0c79c95ac40f2 100644 --- a/examples/platform/silabs/efr32/project_include/OpenThreadConfig.h +++ b/examples/platform/silabs/efr32/project_include/OpenThreadConfig.h @@ -40,7 +40,7 @@ #define OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE 0 // In seconds -#define SL_MLE_TIMEOUT_s (SL_OT_IDLE_INTERVAL / 1000) +#define SL_MLE_TIMEOUT_s (SL_TRANSPORT_IDLE_INTERVAL / 1000) // Timeout after 2 missed checkin or 4 mins if sleep interval is too short. #define OPENTHREAD_CONFIG_MLE_CHILD_TIMEOUT_DEFAULT ((SL_MLE_TIMEOUT_s < 120) ? 240 : ((SL_MLE_TIMEOUT_s * 2) + 1)) diff --git a/examples/platform/silabs/uart.cpp b/examples/platform/silabs/uart.cpp index c460554c6afc57..809c4e53e05b7a 100644 --- a/examples/platform/silabs/uart.cpp +++ b/examples/platform/silabs/uart.cpp @@ -53,7 +53,7 @@ extern "C" { #endif #include "sl_uartdrv_instances.h" #if SL_WIFI -#include "spi_multiplex.h" +#include #endif // SL_WIFI #ifdef SL_CATALOG_UARTDRV_EUSART_PRESENT #include "sl_uartdrv_eusart_vcom_config.h" diff --git a/examples/refrigerator-app/silabs/src/RefrigeratorUI.cpp b/examples/refrigerator-app/silabs/src/RefrigeratorUI.cpp index 655c803f218dc2..f1b7d7698d08fe 100644 --- a/examples/refrigerator-app/silabs/src/RefrigeratorUI.cpp +++ b/examples/refrigerator-app/silabs/src/RefrigeratorUI.cpp @@ -26,10 +26,10 @@ #include "lcd.h" #include -#if SL_WIFI && !defined(SLI_SI91X_MCU_INTERFACE) // Only needed for wifi NCP devices -#include "spi_multiplex.h" -#endif // SL_WIFI +#if SL_WIFI && !defined(SLI_SI91X_MCU_INTERFACE) +#include +#endif // SL_WIFI && !defined(SLI_SI91X_MCU_INTERFACE) // LCD line define constexpr uint8_t kTempLcdInitialX = 30; diff --git a/examples/smoke-co-alarm-app/silabs/openthread.gni b/examples/smoke-co-alarm-app/silabs/openthread.gni index f2a7ab6ed78434..a9b6527c41c351 100644 --- a/examples/smoke-co-alarm-app/silabs/openthread.gni +++ b/examples/smoke-co-alarm-app/silabs/openthread.gni @@ -36,8 +36,8 @@ chip_icd_report_on_active_mode = true chip_enable_icd_lit = true # Openthread Configuration flags -sl_ot_idle_interval_ms = 3600000 # 60mins Idle Polling Interval -sl_ot_active_interval_ms = 1000 # 1000ms Active Polling Interval +sl_transport_idle_interval_ms = 3600000 # 60mins Idle Polling Interval +sl_transport_active_interval_ms = 1000 # 1000ms Active Polling Interval # ICD Matter Configuration flags sl_idle_mode_duration_s = 3600 # 60min Idle Mode Duration diff --git a/examples/thermostat/silabs/src/ThermostatUI.cpp b/examples/thermostat/silabs/src/ThermostatUI.cpp index f82ee36387e99a..4ac0263a0c4eb6 100644 --- a/examples/thermostat/silabs/src/ThermostatUI.cpp +++ b/examples/thermostat/silabs/src/ThermostatUI.cpp @@ -25,10 +25,10 @@ #include "glib.h" #include "lcd.h" -#if SL_WIFI && !defined(SLI_SI91X_MCU_INTERFACE) // Only needed for wifi NCP devices -#include "spi_multiplex.h" -#endif // SL_WIFI +#if SL_WIFI && !defined(SLI_SI91X_MCU_INTERFACE) +#include +#endif // SL_WIFI && !defined(SLI_SI91X_MCU_INTERFACE) // LCD line define constexpr uint8_t kTempLcdInitialX = 30; diff --git a/examples/window-app/silabs/openthread.gni b/examples/window-app/silabs/openthread.gni index 47c5860c9fb10d..0736dc61e4a64b 100644 --- a/examples/window-app/silabs/openthread.gni +++ b/examples/window-app/silabs/openthread.gni @@ -33,8 +33,8 @@ chip_subscription_timeout_resumption = false sl_use_subscription_syncing = true # Openthread Configuration flags -sl_ot_idle_interval_ms = 1000 # 1s Idle Intervals -sl_ot_active_interval_ms = 500 # 500ms Active Intervals +sl_transport_idle_interval_ms = 1000 # 1s Idle Intervals +sl_transport_active_interval_ms = 500 # 500ms Active Intervals # ICD Matter Configuration flags sl_idle_mode_duration_s = 600 # 10min Idle Mode Duration diff --git a/src/platform/silabs/CHIPDevicePlatformConfig.h b/src/platform/silabs/CHIPDevicePlatformConfig.h index 7e86c64694de5b..387c9c934b2f39 100644 --- a/src/platform/silabs/CHIPDevicePlatformConfig.h +++ b/src/platform/silabs/CHIPDevicePlatformConfig.h @@ -169,10 +169,10 @@ #if SL_ICD_ENABLED #ifndef CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL -#define CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL chip::System::Clock::Milliseconds32(SL_OT_IDLE_INTERVAL) +#define CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL chip::System::Clock::Milliseconds32(SL_TRANSPORT_IDLE_INTERVAL) #endif // CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL #ifndef CHIP_DEVICE_CONFIG_ICD_FAST_POLL_INTERVAL -#define CHIP_DEVICE_CONFIG_ICD_FAST_POLL_INTERVAL chip::System::Clock::Milliseconds32(SL_OT_ACTIVE_INTERVAL) +#define CHIP_DEVICE_CONFIG_ICD_FAST_POLL_INTERVAL chip::System::Clock::Milliseconds32(SL_TRANSPORT_ACTIVE_INTERVAL) #endif // CHIP_DEVICE_CONFIG_ICD_FAST_POLL_INTERVAL #endif // SL_ICD_ENABLED diff --git a/src/platform/silabs/SiWx917/SiWxPlatformInterface.h b/src/platform/silabs/SiWx917/SiWxPlatformInterface.h index 8589db3b3f4484..1b654332f11c72 100644 --- a/src/platform/silabs/SiWx917/SiWxPlatformInterface.h +++ b/src/platform/silabs/SiWx917/SiWxPlatformInterface.h @@ -19,6 +19,12 @@ #include +namespace { +#ifdef ENABLE_CHIP_SHELL +bool ps_requirement_added = false; +#endif // ENABLE_CHIP_SHELL +} // namespace + #ifdef __cplusplus extern "C" { #endif @@ -27,6 +33,7 @@ extern "C" { #include "sl_si91x_button.h" #include "sl_si91x_button_pin_config.h" #include "sl_si91x_driver_gpio.h" +#include "sl_si91x_power_manager.h" /** * @brief invoked when button press event is received when in sleep diff --git a/src/platform/silabs/multi-ota/OTACustomProcessor.cpp b/src/platform/silabs/multi-ota/OTACustomProcessor.cpp index 6b87638adb9639..852866e94e03cc 100644 --- a/src/platform/silabs/multi-ota/OTACustomProcessor.cpp +++ b/src/platform/silabs/multi-ota/OTACustomProcessor.cpp @@ -22,12 +22,13 @@ #include +#if SL_WIFI +#include +#endif // SL_WIFI + extern "C" { #include "btl_interface.h" #include "sl_core.h" -#if SL_WIFI -#include "spi_multiplex.h" -#endif // SL_WIFI } /// No error, operation OK diff --git a/src/platform/silabs/multi-ota/OTAFirmwareProcessor.cpp b/src/platform/silabs/multi-ota/OTAFirmwareProcessor.cpp index 07dc974dd7b54d..2f1277a311fdca 100644 --- a/src/platform/silabs/multi-ota/OTAFirmwareProcessor.cpp +++ b/src/platform/silabs/multi-ota/OTAFirmwareProcessor.cpp @@ -22,12 +22,13 @@ #include +#if SL_WIFI +#include +#endif // SL_WIFI + extern "C" { #include "btl_interface.h" #include "sl_core.h" -#if SL_WIFI -#include "spi_multiplex.h" -#endif // SL_WIFI } /// No error, operation OK diff --git a/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.cpp b/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.cpp index 42a9788c2868eb..85859f29fafde6 100644 --- a/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.cpp +++ b/src/platform/silabs/multi-ota/OTAMultiImageProcessorImpl.cpp @@ -30,12 +30,13 @@ using namespace ::chip::DeviceLayer::Internal; static chip::OTAMultiImageProcessorImpl gImageProcessor; +#if SL_WIFI +#include +#endif // SL_WIFI + extern "C" { #include "btl_interface.h" #include "sl_core.h" -#if SL_WIFI -#include "spi_multiplex.h" -#endif // SL_WIFI } namespace chip { diff --git a/src/platform/silabs/wifi/BUILD.gn b/src/platform/silabs/wifi/BUILD.gn index 882a66deb4fa9f..db58633599a9e3 100644 --- a/src/platform/silabs/wifi/BUILD.gn +++ b/src/platform/silabs/wifi/BUILD.gn @@ -31,6 +31,9 @@ declare_args() { #default Wifi Password chip_default_wifi_psk = "" + + # Argument to enable LwIP debug logs + sl_enable_wifi_debug = false } if (chip_enable_wifi && !wifi_soc) { @@ -51,6 +54,12 @@ config("wifi-platform-config") { defines = [] include_dirs = [] + if (sl_enable_wifi_debug) { + defines += [ "WIFI_DEBUG_ENABLED=1" ] + } else { + defines += [ "WIFI_DEBUG_ENABLED=0" ] + } + if (use_rs9116) { # All the stuff from wiseconnect include_dirs += rs911x_inc_plat @@ -65,6 +74,7 @@ config("wifi-platform-config") { "SL_WIFI_SSID=\"${chip_default_wifi_ssid}\"", ] } + if (chip_default_wifi_psk != "") { assert(chip_default_wifi_ssid != "", "ssid can't be null if psk is provided") @@ -120,8 +130,6 @@ source_set("wifi-platform") { # All the stuff from wiseconnect sources += rs9117_src_sapi - - #add compilation flags for rs991x build. This will be addressed directly in wiseconnect sdk in the next version release of that sdk } else if (use_wf200) { sources += wf200_plat_src } @@ -142,6 +150,7 @@ source_set("wifi-platform") { if (use_wf200 || use_rs9116) { sources += [ "${silabs_platform_dir}/wifi/lwip-support/dhcp_client.cpp", + "${silabs_platform_dir}/wifi/lwip-support/dhcp_client.h", "${silabs_platform_dir}/wifi/lwip-support/ethernetif.cpp", "${silabs_platform_dir}/wifi/lwip-support/ethernetif.h", "${silabs_platform_dir}/wifi/lwip-support/lwip_netif.cpp", diff --git a/src/platform/silabs/wifi/SiWx/WifiInterface.cpp b/src/platform/silabs/wifi/SiWx/WifiInterface.cpp index 0b4135a50a7fd1..514af648af07b3 100644 --- a/src/platform/silabs/wifi/SiWx/WifiInterface.cpp +++ b/src/platform/silabs/wifi/SiWx/WifiInterface.cpp @@ -93,9 +93,6 @@ namespace { #if CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE // TODO: should be removed once we are getting the press interrupt for button 0 with sleep bool btn0_pressed = false; -#ifdef ENABLE_CHIP_SHELL -bool ps_requirement_added = false; -#endif // ENABLE_CHIP_SHELL #endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE bool hasNotifiedWifiConnectivity = false; @@ -550,37 +547,6 @@ int32_t sl_wifi_platform_disconnect(void) return sl_net_down((sl_net_interface_t) SL_NET_WIFI_CLIENT_INTERFACE); } -/****************************************************************** - * @fn wfx_rsi_power_save(rsi_power_save_profile_mode_t sl_si91x_ble_state, sl_si91x_performance_profile_t sl_si91x_wifi_state) - * @brief - * Setting the RS911x in DTIM sleep based mode - * - * @param[in] sl_si91x_ble_state : State to set for the BLE - * @param[in] sl_si91x_wifi_state : State to set for the WiFi - * @return - * None - *********************************************************************/ -int32_t wfx_rsi_power_save(rsi_power_save_profile_mode_t sl_si91x_ble_state, sl_si91x_performance_profile_t sl_si91x_wifi_state) -{ - int32_t status; - - status = rsi_bt_power_save_profile(sl_si91x_ble_state, 0); - if (status != RSI_SUCCESS) - { - ChipLogError(DeviceLayer, "rsi_bt_power_save_profile failed: 0x%lx", static_cast(status)); - return status; - } - sl_wifi_performance_profile_t wifi_profile = { .profile = sl_si91x_wifi_state }; - status = sl_wifi_set_performance_profile(&wifi_profile); - if (status != RSI_SUCCESS) - { - ChipLogError(DeviceLayer, "sl_wifi_set_performance_profile failed: 0x%lx", static_cast(status)); - return status; - } - - return status; -} - sl_status_t show_scan_results(sl_wifi_scan_result_t * scan_result) { SL_WIFI_ARGS_CHECK_NULL_POINTER(scan_result); @@ -897,9 +863,23 @@ void wfx_dhcp_got_ipv4(uint32_t ip) * @return SL_STATUS_OK if successful, * SL_STATUS_FAIL otherwise ***********************************************************************/ -sl_status_t wfx_power_save(rsi_power_save_profile_mode_t sl_si91x_ble_state, - sl_si91x_performance_profile_t sl_si91x_wifi_state) // TODO : Figure out why the extern C is necessary +sl_status_t wfx_power_save(rsi_power_save_profile_mode_t sl_si91x_ble_state, sl_si91x_performance_profile_t sl_si91x_wifi_state) { - return (wfx_rsi_power_save(sl_si91x_ble_state, sl_si91x_wifi_state) ? SL_STATUS_FAIL : SL_STATUS_OK); + int32_t error = rsi_bt_power_save_profile(sl_si91x_ble_state, 0); + if (error != RSI_SUCCESS) + { + ChipLogError(DeviceLayer, "rsi_bt_power_save_profile failed: %ld", error); + return SL_STATUS_FAIL; + } + + sl_wifi_performance_profile_t wifi_profile = { .profile = sl_si91x_wifi_state }; + sl_status_t status = sl_wifi_set_performance_profile(&wifi_profile); + if (status != SL_STATUS_OK) + { + ChipLogError(DeviceLayer, "sl_wifi_set_performance_profile failed: 0x%lx", static_cast(status)); + return status; + } + + return SL_STATUS_OK; } #endif diff --git a/src/platform/silabs/wifi/WifiInterfaceAbstraction.cpp b/src/platform/silabs/wifi/WifiInterfaceAbstraction.cpp index 430b9bbddb7d38..698c839a10e43a 100644 --- a/src/platform/silabs/wifi/WifiInterfaceAbstraction.cpp +++ b/src/platform/silabs/wifi/WifiInterfaceAbstraction.cpp @@ -41,7 +41,6 @@ namespace { constexpr uint8_t kWlanMinRetryIntervalsInSec = 1; constexpr uint8_t kWlanMaxRetryIntervalsInSec = 60; -constexpr uint8_t kWlanRetryIntervalInSec = 5; uint8_t retryInterval = kWlanMinRetryIntervalsInSec; osTimerId_t sRetryTimer; @@ -52,7 +51,7 @@ osTimerId_t sRetryTimer; void RetryConnectionTimerHandler(void * arg) { #if CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE - wfx_rsi_power_save(RSI_ACTIVE, HIGH_PERFORMANCE); + wfx_power_save(RSI_ACTIVE, HIGH_PERFORMANCE); #endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE if (wfx_connect_to_ap() != SL_STATUS_OK) { @@ -178,54 +177,23 @@ void wfx_ip_changed_notify(int got_ip) *************************************************************************************/ void wfx_retry_connection(uint16_t retryAttempt) { - // During commissioning, we retry to join the network MAX_JOIN_RETRIES_COUNT - if (/*BaseApplication::sAppDelegate.isCommissioningInProgress()*/ true) + if (retryInterval > kWlanMaxRetryIntervalsInSec) { - if (retryAttempt < MAX_JOIN_RETRIES_COUNT) - { - ChipLogProgress(DeviceLayer, "wfx_retry_connection : Next attempt after %d Seconds", kWlanRetryIntervalInSec); - if (osTimerStart(sRetryTimer, pdMS_TO_TICKS(CONVERT_SEC_TO_MS(kWlanRetryIntervalInSec))) != osOK) - { - ChipLogProgress(DeviceLayer, "Failed to start retry timer"); - // Sending the join command if retry timer failed to start - if (wfx_connect_to_ap() != SL_STATUS_OK) - { - ChipLogError(DeviceLayer, "wfx_connect_to_ap() failed."); - } - return; - } - } - else - { - ChipLogProgress(DeviceLayer, "Connect failed after max %d tries", retryAttempt); - } + retryInterval = kWlanMaxRetryIntervalsInSec; } - else + if (osTimerStart(sRetryTimer, pdMS_TO_TICKS(CONVERT_SEC_TO_MS(retryInterval))) != osOK) { - /* After disconnection or power cycle the DUT - * At the telescopic time interval device try to reconnect with AP, upto WLAN_MAX_RETRY_TIMER_MS intervals - * are telescopic. If interval exceed WLAN_MAX_RETRY_TIMER_MS then it will try to reconnect at - * WLAN_MAX_RETRY_TIMER_MS intervals. - */ - if (retryInterval > kWlanMaxRetryIntervalsInSec) - { - retryInterval = kWlanMaxRetryIntervalsInSec; - } - if (osTimerStart(sRetryTimer, pdMS_TO_TICKS(CONVERT_SEC_TO_MS(retryInterval))) != osOK) + ChipLogProgress(DeviceLayer, "Failed to start retry timer"); + // Sending the join command if retry timer failed to start + if (wfx_connect_to_ap() != SL_STATUS_OK) { - ChipLogProgress(DeviceLayer, "Failed to start retry timer"); - // Sending the join command if retry timer failed to start - if (wfx_connect_to_ap() != SL_STATUS_OK) - { - ChipLogError(DeviceLayer, "wfx_connect_to_ap() failed."); - } - return; + ChipLogError(DeviceLayer, "wfx_connect_to_ap() failed."); } -#if CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE - wfx_rsi_power_save(RSI_SLEEP_MODE_8, STANDBY_POWER_SAVE_WITH_RAM_RETENTION); -#endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE - ChipLogProgress(DeviceLayer, "wfx_retry_connection : Next attempt after %d Seconds", retryInterval); - retryInterval += retryInterval; return; } +#if CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE + wfx_power_save(RSI_SLEEP_MODE_8, STANDBY_POWER_SAVE_WITH_RAM_RETENTION); +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE + ChipLogProgress(DeviceLayer, "wfx_retry_connection : Next attempt after %d Seconds", retryInterval); + retryInterval += retryInterval; } diff --git a/src/platform/silabs/wifi/WifiInterfaceAbstraction.h b/src/platform/silabs/wifi/WifiInterfaceAbstraction.h index f6364d040e5189..012683aef60333 100644 --- a/src/platform/silabs/wifi/WifiInterfaceAbstraction.h +++ b/src/platform/silabs/wifi/WifiInterfaceAbstraction.h @@ -63,11 +63,6 @@ #define GET_IPV6_FAIL (0) #define IP_STATUS_SUCCESS (1) -#define SL_WFX_STARTUP_IND_ID (1) -#define SL_WFX_CONNECT_IND_ID (2) -#define SL_WFX_DISCONNECT_IND_ID (3) -#define SL_WFX_SCAN_COMPLETE_ID (4) - // TASK and Interrupt Macros #define SUCCESS_STATUS (1) @@ -275,14 +270,6 @@ int32_t wfx_rsi_get_ap_ext(wfx_wifi_scan_ext_t * extra_info); int32_t wfx_rsi_reset_count(); int32_t sl_wifi_platform_disconnect(); -#if CHIP_CONFIG_ENABLE_ICD_SERVER -#if SLI_SI917 -int32_t wfx_rsi_power_save(rsi_power_save_profile_mode_t sl_si91x_ble_state, sl_si91x_performance_profile_t sl_si91x_wifi_state); -#else -int32_t wfx_rsi_power_save(); -#endif /* SLI_SI917 */ -#endif /* SL_ICD_ENABLED */ - /** * @brief Posts an event to the Wi-Fi task * @@ -304,7 +291,6 @@ void sl_button_on_change(uint8_t btn, uint8_t btnAction); #ifdef WF200_WIFI void sl_wfx_host_gpio_init(void); void wfx_bus_start(void); -sl_status_t sl_wfx_host_process_event(sl_wfx_generic_message_t * event_payload); #endif /* WF200_WIFI */ #ifdef __cplusplus diff --git a/src/platform/silabs/wifi/lwip-support/ethernetif.cpp b/src/platform/silabs/wifi/lwip-support/ethernetif.cpp index 7e880f62e9a36b..c37d6ab93337e8 100644 --- a/src/platform/silabs/wifi/lwip-support/ethernetif.cpp +++ b/src/platform/silabs/wifi/lwip-support/ethernetif.cpp @@ -140,7 +140,7 @@ static void low_level_input(struct netif * netif, uint8_t * b, uint16_t len) if (!(ip6_addr_ispreferred(netif_ip6_addr_state(netif, 0))) && (memcmp(netif->hwaddr, src_mac, netif->hwaddr_len) == 0) && (memcmp(netif->hwaddr, dst_mac, netif->hwaddr_len) != 0)) { -#ifdef WIFI_DEBUG_ENABLED +#if WIFI_DEBUG_ENABLED ChipLogProgress(DeviceLayer, "lwip_input: DROP, [%02x:%02x:%02x:%02x:%02x:%02x]<-[%02x:%02x:%02x:%02x:%02x:%02x] type=%02x%02x", @@ -163,7 +163,7 @@ static void low_level_input(struct netif * netif, uint8_t * b, uint16_t len) memcpy((uint8_t *) q->payload, (uint8_t *) b + bufferoffset, q->len); bufferoffset += q->len; } -#ifdef WIFI_DEBUG_ENABLED +#if WIFI_DEBUG_ENABLED ChipLogProgress(DeviceLayer, "lwip_input: ACCEPT %ld, [%02x:%02x:%02x:%02x:%02x:%02x]<-[%02x:%02x:%02x:%02x:%02x:%02x] type=%02x%02x", bufferoffset, @@ -255,7 +255,7 @@ static err_t low_level_output(struct netif * netif, struct pbuf * p) int i = 0; result = SL_STATUS_FAIL; -#ifdef WIFI_DEBUG_ENABLED +#if WIFI_DEBUG_ENABLED ChipLogProgress(DeviceLayer, "WF200: Out %d", (int) framelength); #endif @@ -302,7 +302,7 @@ void sl_wfx_host_received_frame_callback(sl_wfx_received_ind_t * rx_buffer) len = rx_buffer->body.frame_length; buffer = (uint8_t *) &(rx_buffer->body.frame[rx_buffer->body.frame_padding]); -#ifdef WIFI_DEBUG_ENABLED +#if WIFI_DEBUG_ENABLED ChipLogProgress(DeviceLayer, "WF200: In %d", (int) len); #endif @@ -310,14 +310,14 @@ void sl_wfx_host_received_frame_callback(sl_wfx_received_ind_t * rx_buffer) } else { -#ifdef WIFI_DEBUG_ENABLED +#if WIFI_DEBUG_ENABLED ChipLogProgress(DeviceLayer, "WF200: NO-INTF"); #endif } } else { -#ifdef WIFI_DEBUG_ENABLED +#if WIFI_DEBUG_ENABLED ChipLogProgress(DeviceLayer, "WF200: Invalid frame IN"); #endif } @@ -354,7 +354,7 @@ static err_t low_level_output(struct netif * netif, struct pbuf * p) struct pbuf * q; uint16_t framelength = 0; uint16_t datalength = 0; -#ifdef WIFI_DEBUG_ENABLED +#if WIFI_DEBUG_ENABLED ChipLogProgress(DeviceLayer, "LWIP : low_level_output"); #endif if (xSemaphoreTake(ethout_sem, portMAX_DELAY) != pdTRUE) @@ -370,7 +370,7 @@ static err_t low_level_output(struct netif * netif, struct pbuf * p) { framelength = LWIP_FRAME_ALIGNMENT; } -#ifdef WIFI_DEBUG_ENABLED +#if WIFI_DEBUG_ENABLED ChipLogProgress(DeviceLayer, "EN-RSI: Output"); #endif if ((netif->flags & (NETIF_FLAG_LINK_UP | NETIF_FLAG_UP)) != (NETIF_FLAG_LINK_UP | NETIF_FLAG_UP)) @@ -387,7 +387,7 @@ static err_t low_level_output(struct netif * netif, struct pbuf * p) return ERR_IF; } -#ifdef WIFI_DEBUG_ENABLED +#if WIFI_DEBUG_ENABLED uint8_t * b = (uint8_t *) p->payload; ChipLogProgress(DeviceLayer, "EN-RSI: Out [%02x:%02x:%02x:%02x:%02x:%02x][%02x:%02x:%02x:%02x:%02x:%02x]type=%02x%02x", b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13]); @@ -403,7 +403,7 @@ static err_t low_level_output(struct netif * netif, struct pbuf * p) /* Add junk data to the end for frame alignment if framelength is less than 60 */ wfx_rsi_pkt_add_data(packet, (uint8_t *) (p->payload), LWIP_FRAME_ALIGNMENT - datalength, datalength); } -#ifdef WIFI_DEBUG_ENABLED +#if WIFI_DEBUG_ENABLED ChipLogProgress(DeviceLayer, "EN-RSI: Sending %d", framelength); #endif @@ -417,7 +417,7 @@ static err_t low_level_output(struct netif * netif, struct pbuf * p) return ERR_IF; } -#ifdef WIFI_DEBUG_ENABLED +#if WIFI_DEBUG_ENABLED ChipLogProgress(DeviceLayer, "EN-RSI:Xmit %d", framelength); #endif xSemaphoreGive(ethout_sem); diff --git a/src/platform/silabs/wifi/rs911x/WifiInterface.cpp b/src/platform/silabs/wifi/rs911x/WifiInterface.cpp index c918b3af362196..8b811534ca3e20 100644 --- a/src/platform/silabs/wifi/rs911x/WifiInterface.cpp +++ b/src/platform/silabs/wifi/rs911x/WifiInterface.cpp @@ -234,39 +234,6 @@ int32_t sl_wifi_platform_disconnect(void) return rsi_wlan_disconnect(); } -#if SL_ICD_ENABLED -/****************************************************************** - * @fn wfx_rsi_power_save(void) - * @brief - * Setting the RS911x in DTIM sleep based mode - * - * @param[in] None - * @return - * None - *********************************************************************/ -int32_t wfx_rsi_power_save(void) -{ - int32_t status; -#ifdef RSI_BLE_ENABLE - status = rsi_bt_power_save_profile(RSI_SLEEP_MODE_2, RSI_MAX_PSP); - if (status != RSI_SUCCESS) - { - ChipLogError(DeviceLayer, "BT Powersave Config Failed, Error Code : 0x%lX", status); - return status; - } -#endif /* RSI_BLE_ENABLE */ - - status = rsi_wlan_power_save_profile(RSI_SLEEP_MODE_2, RSI_MAX_PSP); - if (status != RSI_SUCCESS) - { - ChipLogError(DeviceLayer, "Powersave Config Failed, Error Code : 0x%lX", status); - return status; - } - ChipLogDetail(DeviceLayer, "Powersave Config Success"); - return status; -} -#endif /* SL_ICD_ENABLED */ - /****************************************************************** * @fn wfx_rsi_join_cb(uint16_t status, const uint8_t *buf, const uint16_t len) * @brief @@ -964,8 +931,26 @@ int32_t wfx_rsi_send_data(void * p, uint16_t len) * @return SL_STATUS_OK if successful, * SL_STATUS_FAIL otherwise ***********************************************************************/ -sl_status_t wfx_power_save(void) // TODO : Figure out why the extern C is necessary +sl_status_t wfx_power_save(void) { - return (wfx_rsi_power_save() ? SL_STATUS_FAIL : SL_STATUS_OK); + int32_t status; +#ifdef RSI_BLE_ENABLE + status = rsi_bt_power_save_profile(RSI_SLEEP_MODE_2, RSI_MAX_PSP); + if (status != RSI_SUCCESS) + { + ChipLogError(DeviceLayer, "BT Powersave Config Failed, Error Code : 0x%lX", status); + return SL_STATUS_FAIL; + } +#endif /* RSI_BLE_ENABLE */ + + status = rsi_wlan_power_save_profile(RSI_SLEEP_MODE_2, RSI_MAX_PSP); + if (status != RSI_SUCCESS) + { + ChipLogError(DeviceLayer, "Powersave Config Failed, Error Code : 0x%lX", status); + return SL_STATUS_FAIL; + } + + ChipLogDetail(DeviceLayer, "Powersave Config Success"); + return SL_STATUS_OK; } #endif /* SL_ICD_ENABLED */ diff --git a/src/platform/silabs/wifi/wf200/WifiInterface.cpp b/src/platform/silabs/wifi/wf200/WifiInterface.cpp index fef3cb3a63a022..ebeaa2d4a42ec1 100644 --- a/src/platform/silabs/wifi/wf200/WifiInterface.cpp +++ b/src/platform/silabs/wifi/wf200/WifiInterface.cpp @@ -26,6 +26,7 @@ #include "sl_wfx_cmd_api.h" #include "sl_wfx_constants.h" #include "task.h" +#include #include #include #include @@ -224,16 +225,6 @@ typedef struct __attribute__((__packed__)) sl_wfx_mib_req_s sl_wfx_get_counters_cnf_t * counters; -/**************************************************************************** - * @brief - * get the wifi state - * @return returns wificonetext state - *****************************************************************************/ -sl_wfx_state_t wfx_get_wifi_state(void) -{ - return wifiContext.state; -} - sl_status_t get_all_counters(void) { sl_status_t result; @@ -328,7 +319,7 @@ static void wfx_events_task_start(void) * @returns Returns SL_STATUS_OK if successful, *SL_STATUS_FAIL otherwise *****************************************************************************/ -sl_status_t sl_wfx_host_process_event(sl_wfx_generic_message_t * event_payload) +extern "C" sl_status_t sl_wfx_host_process_event(sl_wfx_generic_message_t * event_payload) { switch (event_payload->header.id) { @@ -739,14 +730,14 @@ static void wfx_events_task(void * p_arg) retryJoin = 0; wfx_lwip_set_sta_link_up(); #if CHIP_CONFIG_ENABLE_ICD_SERVER - if (!(wfx_get_wifi_state() & SL_WFX_AP_INTERFACE_UP)) + if (!(wifiContext.state & SL_WFX_AP_INTERFACE_UP)) { // Enable the power save ChipLogProgress(DeviceLayer, "WF200 going to DTIM based sleep"); sl_wfx_set_power_mode(WFM_PM_MODE_DTIM, WFM_PM_POLL_FAST_PS, BEACON_1, 0 /*timeout*/); sl_wfx_enable_device_power_save(); } -#endif /* CHIP_CONFIG_ENABLE_ICD_SERVER */ +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER } if (flags & SL_WFX_DISCONNECT) diff --git a/src/platform/silabs/wifi/wf200/platform/efr_spi.c b/src/platform/silabs/wifi/wf200/platform/efr_spi.c index 6f80fc83d90984..434253f855dfbf 100644 --- a/src/platform/silabs/wifi/wf200/platform/efr_spi.c +++ b/src/platform/silabs/wifi/wf200/platform/efr_spi.c @@ -437,8 +437,6 @@ sl_status_t sl_wfx_host_post_lcd_spi_transfer(void) #endif // SL_SPICTRL_MUX return SL_STATUS_OK; } -#else -#error still not working #endif // SL_LCDCTRL_MUX #if SL_UARTCTRL_MUX diff --git a/src/platform/silabs/wifi/wf200/platform/sl_wfx_host.h b/src/platform/silabs/wifi/wf200/platform/sl_wfx_host.h index dc9bcd28524623..d33b5fb6801264 100644 --- a/src/platform/silabs/wifi/wf200/platform/sl_wfx_host.h +++ b/src/platform/silabs/wifi/wf200/platform/sl_wfx_host.h @@ -15,6 +15,8 @@ * limitations under the License. */ +// TODO: Should use the file from simplicity sdk + #pragma once #include "FreeRTOS.h" @@ -26,6 +28,7 @@ #ifdef __cplusplus extern "C" { #endif +sl_status_t sl_wfx_host_process_event(sl_wfx_generic_message_t * event_payload); uint8_t sl_wfx_host_get_waited_event(void); sl_status_t wfx_soft_init(void); diff --git a/src/platform/silabs/wifi/wf200/platform/wf200_init.c b/src/platform/silabs/wifi/wf200/platform/wf200_init.c index 40f1aaf08af6bb..92663f9b059e4a 100644 --- a/src/platform/silabs/wifi/wf200/platform/wf200_init.c +++ b/src/platform/silabs/wifi/wf200/platform/wf200_init.c @@ -319,6 +319,7 @@ sl_status_t sl_wfx_host_reset_chip(void) *****************************************************************************/ sl_status_t sl_wfx_host_wait_for_wake_up(void) { + xSemaphoreTake(wfx_wakeup_sem, pdMS_TO_TICKS(0)); xSemaphoreTake(wfx_wakeup_sem, pdMS_TO_TICKS(3)); return SL_STATUS_OK; diff --git a/src/platform/silabs/wifi/wf200/wf200.gni b/src/platform/silabs/wifi/wf200/wf200.gni index 437f9def5d47bb..c8e1308f5fb31a 100644 --- a/src/platform/silabs/wifi/wf200/wf200.gni +++ b/src/platform/silabs/wifi/wf200/wf200.gni @@ -26,5 +26,4 @@ wf200_plat_src = [ "${chip_root}/src/platform/silabs/wifi/wf200/platform/sl_wfx_task.h", "${chip_root}/src/platform/silabs/wifi/wf200/platform/sl_custom_board.h", "${chip_root}/src/platform/silabs/wifi/wf200/platform/spi_multiplex.h", - "${chip_root}/src/platform/silabs/wifi/wf200/platform/sl_wfx_board.h", ] diff --git a/src/platform/silabs/wifi/wfx_msgs.h b/src/platform/silabs/wifi/wfx_msgs.h index af167a1f2c2f95..ec1744c998611b 100644 --- a/src/platform/silabs/wifi/wfx_msgs.h +++ b/src/platform/silabs/wifi/wfx_msgs.h @@ -26,6 +26,15 @@ #include "sl_wfx_api.h" #include "sl_wfx_constants.h" #else + +// These names exists in the Si SDK as typedef enum. If they are present in the WF200 builds, we end up with conflicting +// definitions but no erros because one is a define the other is a typedef enum. This causes different files to use different +// values. +#define SL_WFX_STARTUP_IND_ID (1) +#define SL_WFX_CONNECT_IND_ID (2) +#define SL_WFX_DISCONNECT_IND_ID (3) +#define SL_WFX_SCAN_COMPLETE_ID (4) + typedef struct { uint8_t octet[6]; ///< Table to store a MAC address diff --git a/third_party/silabs/efr32_sdk.gni b/third_party/silabs/efr32_sdk.gni index 9ca85baa47bf5b..40296046cc8bad 100644 --- a/third_party/silabs/efr32_sdk.gni +++ b/third_party/silabs/efr32_sdk.gni @@ -53,8 +53,8 @@ declare_args() { sl_matter_ble_extended_adv = false # ICD Openthread Configuration flags - sl_ot_idle_interval_ms = 15000 # 15s Idle Intervals - sl_ot_active_interval_ms = 200 # 200ms Active Intervals + sl_transport_idle_interval_ms = 15000 # 15s Idle Intervals + sl_transport_active_interval_ms = 200 # 200ms Active Intervals # SSED Specific configurations sl_ot_csl_timeout_sec = 30 # 30s CSL timeout @@ -630,15 +630,12 @@ template("efr32_sdk") { "SL_ACTIVE_MODE_DURATION_MS=${sl_active_mode_duration_ms}", "SL_IDLE_MODE_DURATION_S=${sl_idle_mode_duration_s}", "SL_ICD_SUPPORTED_CLIENTS_PER_FABRIC=${sl_icd_supported_clients_per_fabric}", + "SL_TRANSPORT_IDLE_INTERVAL=${sl_transport_idle_interval_ms}", + "SL_TRANSPORT_ACTIVE_INTERVAL=${sl_transport_active_interval_ms}", ] if (defined(invoker.chip_enable_openthread) && invoker.chip_enable_openthread) { - defines += [ - "SL_OT_IDLE_INTERVAL=${sl_ot_idle_interval_ms}", - "SL_OT_ACTIVE_INTERVAL=${sl_ot_active_interval_ms}", - ] - if (enable_synchronized_sed) { defines += [ "CHIP_DEVICE_CONFIG_THREAD_SSED=1", @@ -646,18 +643,6 @@ template("efr32_sdk") { ] } } - - if (defined(invoker.chip_enable_wifi) && invoker.chip_enable_wifi) { - defines += [ - # Used for wifi devices to get packet details - # TODO: Remove this flag, once the communication is fixed - "WIFI_DEBUG_ENABLED=1", - ] - - # This is kept due to the warning on the LWIP when on demand timer is added - # TODO: remove this flag once the warning is fixed in SiSDK MATTER-3946 - cflags_c = [ "-Wno-implicit-function-declaration" ] - } } if (chip_build_libshell) { # matter shell @@ -1025,7 +1010,6 @@ template("efr32_sdk") { sources += [ "${efr32_sdk_root}/platform/radio/wifi/wfx_fmac_driver/bus/sl_wfx_bus.c", "${efr32_sdk_root}/platform/radio/wifi/wfx_fmac_driver/bus/sl_wfx_bus_spi.c", - "${efr32_sdk_root}/platform/radio/wifi/wfx_fmac_driver/secure_link/sl_wfx_secure_link.c", "${efr32_sdk_root}/platform/radio/wifi/wfx_fmac_driver/sl_wfx.c", ] } From 70f2f3e028bcf21d273c40dc217d6d8fef3b5fc5 Mon Sep 17 00:00:00 2001 From: Mathieu Kardous <84793247+mkardous-silabs@users.noreply.github.com> Date: Thu, 28 Nov 2024 07:02:14 -0500 Subject: [PATCH 14/26] [Silabs] Move Wi-Fi interface files to the final structure (#36644) * Move files * Move wifi files to their final location & cleanup * Restyled by clang-format * rename directories * rename paths for new locations * Restyled by clang-format * update include path with the structure --------- Co-authored-by: Restyled.io --- examples/platform/silabs/display/demo-ui.c | 2 +- .../silabs/efr32/OTAImageProcessorImpl.cpp | 2 +- src/platform/silabs/wifi/BUILD.gn | 2 +- .../silabs/wifi/SiWx/WifiInterface.cpp | 2 +- .../platform => SiWx/ncp}/efx32_ncp_host.c | 4 +-- .../wifi/{rs911x => SiWx/ncp}/rs9117.gni | 11 +++----- .../ncp/sl_board_configuration.h} | 17 ++++++++++++ .../ncp}/sl_si91x_ncp_utility.c | 3 --- .../ncp}/sl_si91x_ncp_utility.h | 19 ++++---------- .../{wf200/platform => ncp}/spi_multiplex.h | 0 .../wifi/rs911x/{platform => ncp}/efx_spi.c | 2 +- .../rsi_board_configuration.h | 0 .../wifi/rs911x/{platform => ncp}/rsi_hal.h | 0 .../{platform => ncp}/rsi_hal_mcu_interrupt.c | 26 +++++-------------- .../{platform => ncp}/rsi_hal_mcu_ioports.c | 16 +++++------- .../{platform => ncp}/rsi_hal_mcu_rtc.c | 0 .../{platform => ncp}/rsi_hal_mcu_timer.c | 0 .../wifi/rs911x/{ => ncp}/rsi_wlan_config.h | 11 +------- .../sl_board_configuration.h | 0 src/platform/silabs/wifi/rs911x/rs911x.gni | 12 ++++----- .../silabs/wifi/wf200/WifiInterface.cpp | 6 ++--- .../wifi/wf200/{platform => ncp}/efr_spi.c | 2 +- .../wf200/{platform => ncp}/sl_custom_board.h | 0 .../wf200/{platform => ncp}/sl_wfx_board.h | 0 .../wf200/{platform => ncp}/sl_wfx_host.h | 0 .../wf200/{platform => ncp}/sl_wfx_task.c | 0 .../wf200/{platform => ncp}/sl_wfx_task.h | 0 .../wifi/wf200/{platform => ncp}/wf200_init.c | 0 src/platform/silabs/wifi/wf200/wf200.gni | 16 ++++++------ third_party/silabs/efr32_sdk.gni | 5 +--- 30 files changed, 67 insertions(+), 91 deletions(-) rename src/platform/silabs/wifi/{rs911x/platform => SiWx/ncp}/efx32_ncp_host.c (96%) rename src/platform/silabs/wifi/{rs911x => SiWx/ncp}/rs9117.gni (86%) rename src/platform/silabs/wifi/{rs911x/platform/sl_board_configuration_SiWx917.h => SiWx/ncp/sl_board_configuration.h} (74%) rename src/platform/silabs/wifi/{rs911x/platform => SiWx/ncp}/sl_si91x_ncp_utility.c (96%) rename src/platform/silabs/wifi/{rs911x/platform => SiWx/ncp}/sl_si91x_ncp_utility.h (75%) rename src/platform/silabs/wifi/{wf200/platform => ncp}/spi_multiplex.h (100%) rename src/platform/silabs/wifi/rs911x/{platform => ncp}/efx_spi.c (99%) rename src/platform/silabs/wifi/rs911x/{platform => ncp}/rsi_board_configuration.h (100%) rename src/platform/silabs/wifi/rs911x/{platform => ncp}/rsi_hal.h (100%) rename src/platform/silabs/wifi/rs911x/{platform => ncp}/rsi_hal_mcu_interrupt.c (95%) rename src/platform/silabs/wifi/rs911x/{platform => ncp}/rsi_hal_mcu_ioports.c (99%) rename src/platform/silabs/wifi/rs911x/{platform => ncp}/rsi_hal_mcu_rtc.c (100%) rename src/platform/silabs/wifi/rs911x/{platform => ncp}/rsi_hal_mcu_timer.c (100%) rename src/platform/silabs/wifi/rs911x/{ => ncp}/rsi_wlan_config.h (97%) rename src/platform/silabs/wifi/rs911x/{platform => ncp}/sl_board_configuration.h (100%) rename src/platform/silabs/wifi/wf200/{platform => ncp}/efr_spi.c (99%) rename src/platform/silabs/wifi/wf200/{platform => ncp}/sl_custom_board.h (100%) rename src/platform/silabs/wifi/wf200/{platform => ncp}/sl_wfx_board.h (100%) rename src/platform/silabs/wifi/wf200/{platform => ncp}/sl_wfx_host.h (100%) rename src/platform/silabs/wifi/wf200/{platform => ncp}/sl_wfx_task.c (100%) rename src/platform/silabs/wifi/wf200/{platform => ncp}/sl_wfx_task.h (100%) rename src/platform/silabs/wifi/wf200/{platform => ncp}/wf200_init.c (100%) diff --git a/examples/platform/silabs/display/demo-ui.c b/examples/platform/silabs/display/demo-ui.c index fb41a5b3097583..fac00dc0d84f95 100644 --- a/examples/platform/silabs/display/demo-ui.c +++ b/examples/platform/silabs/display/demo-ui.c @@ -27,7 +27,7 @@ #include "sl_memlcd.h" #include #if SL_WIFI && !SLI_SI91X_MCU_INTERFACE -#include +#include #endif // SL_WIFI && !SLI_SI91X_MCU_INTERFACE #include diff --git a/src/platform/silabs/efr32/OTAImageProcessorImpl.cpp b/src/platform/silabs/efr32/OTAImageProcessorImpl.cpp index a884071560fb59..09d37d0ca7380d 100644 --- a/src/platform/silabs/efr32/OTAImageProcessorImpl.cpp +++ b/src/platform/silabs/efr32/OTAImageProcessorImpl.cpp @@ -22,7 +22,7 @@ #include #if SL_WIFI -#include +#include #endif // SL_WIFI extern "C" { diff --git a/src/platform/silabs/wifi/BUILD.gn b/src/platform/silabs/wifi/BUILD.gn index db58633599a9e3..304fa89cd2e9c3 100644 --- a/src/platform/silabs/wifi/BUILD.gn +++ b/src/platform/silabs/wifi/BUILD.gn @@ -43,7 +43,7 @@ if (chip_enable_wifi && !wifi_soc) { if (use_rs9116) { import("${silabs_platform_dir}/wifi/rs911x/rs911x.gni") } else if (use_SiWx917) { - import("${silabs_platform_dir}/wifi/rs911x/rs9117.gni") + import("${silabs_platform_dir}/wifi/SiWx/ncp/rs9117.gni") } if (use_wf200) { import("${silabs_platform_dir}/wifi/wf200/wf200.gni") diff --git a/src/platform/silabs/wifi/SiWx/WifiInterface.cpp b/src/platform/silabs/wifi/SiWx/WifiInterface.cpp index 514af648af07b3..291c9988d83215 100644 --- a/src/platform/silabs/wifi/SiWx/WifiInterface.cpp +++ b/src/platform/silabs/wifi/SiWx/WifiInterface.cpp @@ -67,7 +67,7 @@ extern "C" { #if (EXP_BOARD) #include "rsi_bt_common_apis.h" -#include +#include #endif #if CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI91X_MCU_INTERFACE diff --git a/src/platform/silabs/wifi/rs911x/platform/efx32_ncp_host.c b/src/platform/silabs/wifi/SiWx/ncp/efx32_ncp_host.c similarity index 96% rename from src/platform/silabs/wifi/rs911x/platform/efx32_ncp_host.c rename to src/platform/silabs/wifi/SiWx/ncp/efx32_ncp_host.c index c7173763d5f96c..8991ffa8e6a6b4 100644 --- a/src/platform/silabs/wifi/rs911x/platform/efx32_ncp_host.c +++ b/src/platform/silabs/wifi/SiWx/ncp/efx32_ncp_host.c @@ -22,7 +22,6 @@ #include "em_gpio.h" #include "em_usart.h" #include "gpiointerrupt.h" -#include "sl_board_configuration_SiWx917.h" #include "sl_constants.h" #include "sl_rsi_utility.h" #include "sl_si91x_host_interface.h" @@ -30,7 +29,8 @@ #include "sl_si91x_status.h" #include "sl_status.h" #include "sl_wifi_constants.h" -#include +#include +#include #include #include diff --git a/src/platform/silabs/wifi/rs911x/rs9117.gni b/src/platform/silabs/wifi/SiWx/ncp/rs9117.gni similarity index 86% rename from src/platform/silabs/wifi/rs911x/rs9117.gni rename to src/platform/silabs/wifi/SiWx/ncp/rs9117.gni index cbeaf98698c705..6be9a7337af3d2 100644 --- a/src/platform/silabs/wifi/rs911x/rs9117.gni +++ b/src/platform/silabs/wifi/SiWx/ncp/rs9117.gni @@ -18,17 +18,14 @@ import("${silabs_sdk_build_root}/efr32_sdk.gni") rs911x_src_plat = [ "${chip_root}/src/platform/silabs/wifi/SiWx/WifiInterface.cpp", - "${chip_root}/src/platform/silabs/wifi/rs911x/platform/rsi_hal_mcu_interrupt.c", - "${chip_root}/src/platform/silabs/wifi/rs911x/platform/sl_si91x_ncp_utility.c", - "${chip_root}/src/platform/silabs/wifi/rs911x/platform/sl_board_configuration.h", + "${chip_root}/src/platform/silabs/wifi/SiWx/ncp/sl_si91x_ncp_utility.c", + "${chip_root}/src/platform/silabs/wifi/SiWx/ncp/sl_board_configuration.h", "${chip_root}/src/platform/silabs/wifi/wiseconnect-abstraction/WiseconnectInterfaceAbstraction.cpp", "${chip_root}/src/platform/silabs/wifi/wiseconnect-abstraction/WiseconnectInterfaceAbstraction.h", - - # TODO: We shouldn't need a file form the WF200 for the SiWx917 NCP builds - "${chip_root}/src/platform/silabs/wifi/wf200/platform/spi_multiplex.h", + "${chip_root}/src/platform/silabs/wifi/ncp/spi_multiplex.h", # TODO : We should be using the file from the Wiseconnect SDK and not our copy of it. - "${chip_root}/src/platform/silabs/wifi/rs911x/platform/efx32_ncp_host.c", + "${chip_root}/src/platform/silabs/wifi/SiWx/ncp/efx32_ncp_host.c", ] rs9117_inc_plat = [ "${wifi_sdk_root}/components/si91x/ble/inc" ] diff --git a/src/platform/silabs/wifi/rs911x/platform/sl_board_configuration_SiWx917.h b/src/platform/silabs/wifi/SiWx/ncp/sl_board_configuration.h similarity index 74% rename from src/platform/silabs/wifi/rs911x/platform/sl_board_configuration_SiWx917.h rename to src/platform/silabs/wifi/SiWx/ncp/sl_board_configuration.h index 7145e318b33d30..0aad8bd4e863cd 100644 --- a/src/platform/silabs/wifi/rs911x/platform/sl_board_configuration_SiWx917.h +++ b/src/platform/silabs/wifi/SiWx/ncp/sl_board_configuration.h @@ -1,3 +1,20 @@ +/* + * + * 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. + */ + #pragma once #ifdef SL_UART diff --git a/src/platform/silabs/wifi/rs911x/platform/sl_si91x_ncp_utility.c b/src/platform/silabs/wifi/SiWx/ncp/sl_si91x_ncp_utility.c similarity index 96% rename from src/platform/silabs/wifi/rs911x/platform/sl_si91x_ncp_utility.c rename to src/platform/silabs/wifi/SiWx/ncp/sl_si91x_ncp_utility.c index 1d1ab1409c4161..50b8ffdba0993a 100644 --- a/src/platform/silabs/wifi/rs911x/platform/sl_si91x_ncp_utility.c +++ b/src/platform/silabs/wifi/SiWx/ncp/sl_si91x_ncp_utility.c @@ -15,9 +15,6 @@ * limitations under the License. */ -/** - * Includes - */ #include #include #include diff --git a/src/platform/silabs/wifi/rs911x/platform/sl_si91x_ncp_utility.h b/src/platform/silabs/wifi/SiWx/ncp/sl_si91x_ncp_utility.h similarity index 75% rename from src/platform/silabs/wifi/rs911x/platform/sl_si91x_ncp_utility.h rename to src/platform/silabs/wifi/SiWx/ncp/sl_si91x_ncp_utility.h index b434e35f82dbbd..437be2dcb03a1f 100644 --- a/src/platform/silabs/wifi/rs911x/platform/sl_si91x_ncp_utility.h +++ b/src/platform/silabs/wifi/SiWx/ncp/sl_si91x_ncp_utility.h @@ -21,24 +21,16 @@ * devices such as External Flash and LCD. * That can be extended to other families as well. */ -#ifndef SL_SI91X_NCP_UTILITY_H -#define SL_SI91X_NCP_UTILITY_H - #pragma once + #include "FreeRTOS.h" +#include "em_usart.h" #include "semphr.h" #include "silabs_utils.h" -#include "sl_status.h" - -// TODO: This is a WF200 specific include. It is not clear why we need this in the 917 NCP files. -#include - -#if defined(CHIP_9117) -#include "em_usart.h" -#include "sl_board_configuration_SiWx917.h" #include "sl_spidrv_exp_config.h" - -#endif // CHIP_9117 +#include "sl_status.h" +#include +#include #define USART_INITSYNC_BAUDRATE 12500000 @@ -48,4 +40,3 @@ sl_status_t spi_board_init(void); extern uint32_t rx_ldma_channel; extern uint32_t tx_ldma_channel; -#endif // SL_SI91X_NCP_UTILITY_H diff --git a/src/platform/silabs/wifi/wf200/platform/spi_multiplex.h b/src/platform/silabs/wifi/ncp/spi_multiplex.h similarity index 100% rename from src/platform/silabs/wifi/wf200/platform/spi_multiplex.h rename to src/platform/silabs/wifi/ncp/spi_multiplex.h diff --git a/src/platform/silabs/wifi/rs911x/platform/efx_spi.c b/src/platform/silabs/wifi/rs911x/ncp/efx_spi.c similarity index 99% rename from src/platform/silabs/wifi/rs911x/platform/efx_spi.c rename to src/platform/silabs/wifi/rs911x/ncp/efx_spi.c index a339f711a41f35..2467bd311d9015 100644 --- a/src/platform/silabs/wifi/rs911x/platform/efx_spi.c +++ b/src/platform/silabs/wifi/rs911x/ncp/efx_spi.c @@ -34,7 +34,7 @@ #include "sl_status.h" #include "spidrv.h" #include "task.h" -#include +#include #ifdef SL_BOARD_NAME #include "sl_board_control.h" diff --git a/src/platform/silabs/wifi/rs911x/platform/rsi_board_configuration.h b/src/platform/silabs/wifi/rs911x/ncp/rsi_board_configuration.h similarity index 100% rename from src/platform/silabs/wifi/rs911x/platform/rsi_board_configuration.h rename to src/platform/silabs/wifi/rs911x/ncp/rsi_board_configuration.h diff --git a/src/platform/silabs/wifi/rs911x/platform/rsi_hal.h b/src/platform/silabs/wifi/rs911x/ncp/rsi_hal.h similarity index 100% rename from src/platform/silabs/wifi/rs911x/platform/rsi_hal.h rename to src/platform/silabs/wifi/rs911x/ncp/rsi_hal.h diff --git a/src/platform/silabs/wifi/rs911x/platform/rsi_hal_mcu_interrupt.c b/src/platform/silabs/wifi/rs911x/ncp/rsi_hal_mcu_interrupt.c similarity index 95% rename from src/platform/silabs/wifi/rs911x/platform/rsi_hal_mcu_interrupt.c rename to src/platform/silabs/wifi/rs911x/ncp/rsi_hal_mcu_interrupt.c index 8bd277e6242c4d..d1d1bd2aaef4bf 100644 --- a/src/platform/silabs/wifi/rs911x/platform/rsi_hal_mcu_interrupt.c +++ b/src/platform/silabs/wifi/rs911x/ncp/rsi_hal_mcu_interrupt.c @@ -15,10 +15,7 @@ * limitations under the License. */ -#include -#include -#include - +#include "FreeRTOS.h" #include "dmadrv.h" #include "em_chip.h" #include "em_cmu.h" @@ -27,25 +24,16 @@ #include "em_gpio.h" #include "em_ldma.h" #include "em_usart.h" +#include "event_groups.h" #include "gpiointerrupt.h" +#include "rsi_board_configuration.h" +#include "rsi_driver.h" #include "sl_device_init_clocks.h" #include "sl_status.h" - -#include "FreeRTOS.h" -#include "event_groups.h" #include "task.h" - -#if (SLI_SI91X_MCU_INTERFACE | EXP_BOARD) -#include "sl_board_configuration.h" - -#include "sl_rsi_utility.h" -#include "sl_si91x_host_interface.h" - -void gpio_interrupt(uint8_t interrupt_number); -#else -#include "rsi_board_configuration.h" -#include "rsi_driver.h" -#endif +#include +#include +#include typedef void (*UserIntCallBack_t)(void); UserIntCallBack_t call_back, gpio_callback; diff --git a/src/platform/silabs/wifi/rs911x/platform/rsi_hal_mcu_ioports.c b/src/platform/silabs/wifi/rs911x/ncp/rsi_hal_mcu_ioports.c similarity index 99% rename from src/platform/silabs/wifi/rs911x/platform/rsi_hal_mcu_ioports.c rename to src/platform/silabs/wifi/rs911x/ncp/rsi_hal_mcu_ioports.c index ba517b417bdff7..5e4089d127f512 100644 --- a/src/platform/silabs/wifi/rs911x/platform/rsi_hal_mcu_ioports.c +++ b/src/platform/silabs/wifi/rs911x/ncp/rsi_hal_mcu_ioports.c @@ -15,10 +15,7 @@ * limitations under the License. */ -#include -#include -#include - +#include "FreeRTOS.h" #include "dmadrv.h" #include "em_chip.h" #include "em_cmu.h" @@ -27,16 +24,17 @@ #include "em_gpio.h" #include "em_ldma.h" #include "em_usart.h" +#include "event_groups.h" #include "gpiointerrupt.h" +#include "rsi_board_configuration.h" +#include "rsi_driver.h" #include "sl_device_init_clocks.h" #include "sl_status.h" - -#include "FreeRTOS.h" -#include "event_groups.h" #include "task.h" +#include +#include +#include -#include "rsi_board_configuration.h" -#include "rsi_driver.h" /*===========================================================*/ /** * @fn void rsi_hal_config_gpio(uint8_t gpio_number,uint8_t mode,uint8_t value) diff --git a/src/platform/silabs/wifi/rs911x/platform/rsi_hal_mcu_rtc.c b/src/platform/silabs/wifi/rs911x/ncp/rsi_hal_mcu_rtc.c similarity index 100% rename from src/platform/silabs/wifi/rs911x/platform/rsi_hal_mcu_rtc.c rename to src/platform/silabs/wifi/rs911x/ncp/rsi_hal_mcu_rtc.c diff --git a/src/platform/silabs/wifi/rs911x/platform/rsi_hal_mcu_timer.c b/src/platform/silabs/wifi/rs911x/ncp/rsi_hal_mcu_timer.c similarity index 100% rename from src/platform/silabs/wifi/rs911x/platform/rsi_hal_mcu_timer.c rename to src/platform/silabs/wifi/rs911x/ncp/rsi_hal_mcu_timer.c diff --git a/src/platform/silabs/wifi/rs911x/rsi_wlan_config.h b/src/platform/silabs/wifi/rs911x/ncp/rsi_wlan_config.h similarity index 97% rename from src/platform/silabs/wifi/rs911x/rsi_wlan_config.h rename to src/platform/silabs/wifi/rs911x/ncp/rsi_wlan_config.h index b851cd79580a22..6e14347fac05b7 100644 --- a/src/platform/silabs/wifi/rs911x/rsi_wlan_config.h +++ b/src/platform/silabs/wifi/rs911x/ncp/rsi_wlan_config.h @@ -46,18 +46,9 @@ //! To set Extended custom feature select bit map #if WIFI_ENABLE_SECURITY_WPA3_TRANSITION -#ifdef CHIP_9117 -#define RSI_EXT_CUSTOM_FEATURE_BIT_MAP \ - (EXT_FEAT_448K_M4SS_256K | EXT_FEAT_LOW_POWER_MODE | EXT_FEAT_XTAL_CLK_ENABLE | EXT_FEAT_IEEE_80211W) -#else /* !CHIP_9117 */ #define RSI_EXT_CUSTOM_FEATURE_BIT_MAP (EXT_FEAT_384K_MODE | EXT_FEAT_IEEE_80211W) -#endif /* CHIP_9117 */ -#else /* !WIFI_ENABLE_SECURITY_WPA3_TRANSITION */ -#ifdef CHIP_9117 -#define RSI_EXT_CUSTOM_FEATURE_BIT_MAP (EXT_FEAT_448K_M4SS_256K | EXT_FEAT_LOW_POWER_MODE | EXT_FEAT_XTAL_CLK_ENABLE) -#else /* !CHIP_9117 */ +#else /* !WIFI_ENABLE_SECURITY_WPA3_TRANSITION */ #define RSI_EXT_CUSTOM_FEATURE_BIT_MAP EXT_FEAT_384K_MODE -#endif /* CHIP_9117 */ #endif /* WIFI_ENABLE_SECURITY_WPA3_TRANSITION */ //! To set Extended TCPIP feature select bit map diff --git a/src/platform/silabs/wifi/rs911x/platform/sl_board_configuration.h b/src/platform/silabs/wifi/rs911x/ncp/sl_board_configuration.h similarity index 100% rename from src/platform/silabs/wifi/rs911x/platform/sl_board_configuration.h rename to src/platform/silabs/wifi/rs911x/ncp/sl_board_configuration.h diff --git a/src/platform/silabs/wifi/rs911x/rs911x.gni b/src/platform/silabs/wifi/rs911x/rs911x.gni index 3daba8b049c802..54a53fb7da7361 100644 --- a/src/platform/silabs/wifi/rs911x/rs911x.gni +++ b/src/platform/silabs/wifi/rs911x/rs911x.gni @@ -18,12 +18,12 @@ import("${silabs_sdk_build_root}/efr32_sdk.gni") rs911x_src_plat = [ "${chip_root}/src/platform/silabs/wifi/rs911x/WifiInterface.cpp", - "${chip_root}/src/platform/silabs/wifi/rs911x/platform/rsi_hal_mcu_interrupt.c", - "${chip_root}/src/platform/silabs/wifi/rs911x/platform/rsi_hal_mcu_ioports.c", - "${chip_root}/src/platform/silabs/wifi/rs911x/platform/rsi_hal_mcu_timer.c", - "${chip_root}/src/platform/silabs/wifi/rs911x/platform/efx_spi.c", - "${chip_root}/src/platform/silabs/wifi/rs911x/platform/rsi_board_configuration.h", - "${chip_root}/src/platform/silabs/wifi/rs911x/platform/rsi_hal.h", + "${chip_root}/src/platform/silabs/wifi/rs911x/ncp/rsi_hal_mcu_interrupt.c", + "${chip_root}/src/platform/silabs/wifi/rs911x/ncp/rsi_hal_mcu_ioports.c", + "${chip_root}/src/platform/silabs/wifi/rs911x/ncp/rsi_hal_mcu_timer.c", + "${chip_root}/src/platform/silabs/wifi/rs911x/ncp/efx_spi.c", + "${chip_root}/src/platform/silabs/wifi/rs911x/ncp/rsi_board_configuration.h", + "${chip_root}/src/platform/silabs/wifi/rs911x/ncp/rsi_hal.h", "${chip_root}/src/platform/silabs/wifi/wiseconnect-abstraction/WiseconnectInterfaceAbstraction.cpp", ] diff --git a/src/platform/silabs/wifi/wf200/WifiInterface.cpp b/src/platform/silabs/wifi/wf200/WifiInterface.cpp index ebeaa2d4a42ec1..1ff37ab61727b6 100644 --- a/src/platform/silabs/wifi/wf200/WifiInterface.cpp +++ b/src/platform/silabs/wifi/wf200/WifiInterface.cpp @@ -33,9 +33,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/platform/silabs/wifi/wf200/platform/efr_spi.c b/src/platform/silabs/wifi/wf200/ncp/efr_spi.c similarity index 99% rename from src/platform/silabs/wifi/wf200/platform/efr_spi.c rename to src/platform/silabs/wifi/wf200/ncp/efr_spi.c index 434253f855dfbf..55f781d96061b8 100644 --- a/src/platform/silabs/wifi/wf200/platform/efr_spi.c +++ b/src/platform/silabs/wifi/wf200/ncp/efr_spi.c @@ -32,7 +32,7 @@ #include "sl_wfx_host_api.h" #include "sl_wfx_task.h" #include "spidrv.h" -#include +#include #include #include #include diff --git a/src/platform/silabs/wifi/wf200/platform/sl_custom_board.h b/src/platform/silabs/wifi/wf200/ncp/sl_custom_board.h similarity index 100% rename from src/platform/silabs/wifi/wf200/platform/sl_custom_board.h rename to src/platform/silabs/wifi/wf200/ncp/sl_custom_board.h diff --git a/src/platform/silabs/wifi/wf200/platform/sl_wfx_board.h b/src/platform/silabs/wifi/wf200/ncp/sl_wfx_board.h similarity index 100% rename from src/platform/silabs/wifi/wf200/platform/sl_wfx_board.h rename to src/platform/silabs/wifi/wf200/ncp/sl_wfx_board.h diff --git a/src/platform/silabs/wifi/wf200/platform/sl_wfx_host.h b/src/platform/silabs/wifi/wf200/ncp/sl_wfx_host.h similarity index 100% rename from src/platform/silabs/wifi/wf200/platform/sl_wfx_host.h rename to src/platform/silabs/wifi/wf200/ncp/sl_wfx_host.h diff --git a/src/platform/silabs/wifi/wf200/platform/sl_wfx_task.c b/src/platform/silabs/wifi/wf200/ncp/sl_wfx_task.c similarity index 100% rename from src/platform/silabs/wifi/wf200/platform/sl_wfx_task.c rename to src/platform/silabs/wifi/wf200/ncp/sl_wfx_task.c diff --git a/src/platform/silabs/wifi/wf200/platform/sl_wfx_task.h b/src/platform/silabs/wifi/wf200/ncp/sl_wfx_task.h similarity index 100% rename from src/platform/silabs/wifi/wf200/platform/sl_wfx_task.h rename to src/platform/silabs/wifi/wf200/ncp/sl_wfx_task.h diff --git a/src/platform/silabs/wifi/wf200/platform/wf200_init.c b/src/platform/silabs/wifi/wf200/ncp/wf200_init.c similarity index 100% rename from src/platform/silabs/wifi/wf200/platform/wf200_init.c rename to src/platform/silabs/wifi/wf200/ncp/wf200_init.c diff --git a/src/platform/silabs/wifi/wf200/wf200.gni b/src/platform/silabs/wifi/wf200/wf200.gni index c8e1308f5fb31a..0d166b1db49599 100644 --- a/src/platform/silabs/wifi/wf200/wf200.gni +++ b/src/platform/silabs/wifi/wf200/wf200.gni @@ -18,12 +18,12 @@ import("${silabs_sdk_build_root}/efr32_sdk.gni") wf200_plat_src = [ "${chip_root}/src/platform/silabs/wifi/wf200/WifiInterface.cpp", - "${chip_root}/src/platform/silabs/wifi/wf200/platform/sl_wfx_task.c", - "${chip_root}/src/platform/silabs/wifi/wf200/platform/wf200_init.c", - "${chip_root}/src/platform/silabs/wifi/wf200/platform/efr_spi.c", - "${chip_root}/src/platform/silabs/wifi/wf200/platform/sl_wfx_board.h", - "${chip_root}/src/platform/silabs/wifi/wf200/platform/sl_wfx_host.h", - "${chip_root}/src/platform/silabs/wifi/wf200/platform/sl_wfx_task.h", - "${chip_root}/src/platform/silabs/wifi/wf200/platform/sl_custom_board.h", - "${chip_root}/src/platform/silabs/wifi/wf200/platform/spi_multiplex.h", + "${chip_root}/src/platform/silabs/wifi/wf200/ncp/sl_wfx_task.c", + "${chip_root}/src/platform/silabs/wifi/wf200/ncp/wf200_init.c", + "${chip_root}/src/platform/silabs/wifi/wf200/ncp/efr_spi.c", + "${chip_root}/src/platform/silabs/wifi/wf200/ncp/sl_wfx_board.h", + "${chip_root}/src/platform/silabs/wifi/wf200/ncp/sl_wfx_host.h", + "${chip_root}/src/platform/silabs/wifi/wf200/ncp/sl_wfx_task.h", + "${chip_root}/src/platform/silabs/wifi/wf200/ncp/sl_custom_board.h", + "${chip_root}/src/platform/silabs/wifi/ncp/spi_multiplex.h", ] diff --git a/third_party/silabs/efr32_sdk.gni b/third_party/silabs/efr32_sdk.gni index 40296046cc8bad..7861e827d7bdfb 100644 --- a/third_party/silabs/efr32_sdk.gni +++ b/third_party/silabs/efr32_sdk.gni @@ -370,10 +370,7 @@ template("efr32_sdk") { if (use_rs9116) { # TODO: we should create a seperate directory for headers that are necessary for the underlying sdks - _include_dirs += [ - "${chip_root}/src/platform/silabs/wifi/rs911x/platform", - "${chip_root}/src/platform/silabs/wifi/rs911x", - ] + _include_dirs += [ "${chip_root}/src/platform/silabs/wifi/rs911x/ncp" ] } if (use_rs9116 || use_SiWx917) { From 7805664ee3705ec8abe076eebe49450ae0ccf19d Mon Sep 17 00:00:00 2001 From: Arkadiusz Bokowy Date: Thu, 28 Nov 2024 13:03:32 +0100 Subject: [PATCH 15/26] Deliver SIGINT to the shell thread to interrupt read() (#36533) * Deliver SIGINT to the sell thread to interrupt read() * Verify that TV apps exit cleanly * TV casting app with proper shutdown on SIGTERM * Fix import * Revert sigaction() usage, as it seems not to work on Darwin * Remove ifdefs * Use signal() instead of sigaction() on Darwin * Restyled by clang-format --------- Co-authored-by: Restyled.io --- examples/platform/linux/AppMain.cpp | 48 ++++++++++++---- examples/tv-casting-app/linux/main.cpp | 59 +++++++++++++++++++- examples/tv-casting-app/linux/simple-app.cpp | 57 ++++++++++++++++++- scripts/tests/run_tv_casting_test.py | 17 +----- src/lib/shell/Engine.h | 8 +++ src/lib/shell/MainLoopAmeba.cpp | 2 +- src/lib/shell/MainLoopDefault.cpp | 21 +++++-- src/lib/shell/MainLoopESP32.cpp | 2 +- src/lib/shell/MainLoopMW320.cpp | 2 +- src/lib/shell/MainLoopSilabs.cpp | 2 +- 10 files changed, 178 insertions(+), 40 deletions(-) diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp index 65763dc12d3475..b9c0cdf771b772 100644 --- a/examples/platform/linux/AppMain.cpp +++ b/examples/platform/linux/AppMain.cpp @@ -305,7 +305,7 @@ void StopMainEventLoop() else { Server::GetInstance().GenerateShutDownEvent(); - PlatformMgr().ScheduleWork([](intptr_t) { PlatformMgr().StopEventLoopTask(); }); + SystemLayer().ScheduleLambda([]() { PlatformMgr().StopEventLoopTask(); }); } } @@ -318,18 +318,13 @@ void Cleanup() // TODO(16968): Lifecycle management of storage-using components like GroupDataProvider, etc } -// TODO(#20664) REPL test will fail if signal SIGINT is not caught, temporarily keep following logic. - -// when the shell is enabled, don't intercept signals since it prevents the user from -// using expected commands like CTRL-C to quit the application. (see issue #17845) -// We should stop using signals for those faults, and move to a different notification -// means, like a pipe. (see issue #19114) -#if !defined(ENABLE_CHIP_SHELL) void StopSignalHandler(int /* signal */) { +#if defined(ENABLE_CHIP_SHELL) + Engine::Root().StopMainLoop(); +#endif StopMainEventLoop(); } -#endif // !defined(ENABLE_CHIP_SHELL) } // namespace @@ -409,6 +404,18 @@ int ChipLinuxAppInit(int argc, char * const argv[], OptionSet * customOptions, SuccessOrExit(err); #endif +#if defined(ENABLE_CHIP_SHELL) + /* Block SIGINT and SIGTERM. Other threads created by the main thread + * will inherit the signal mask. Then we can explicitly unblock signals + * in the shell thread to handle them, so the read(stdin) call can be + * interrupted by a signal. */ + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + pthread_sigmask(SIG_BLOCK, &set, nullptr); +#endif + err = DeviceLayer::PlatformMgr().InitChipStack(); SuccessOrExit(err); @@ -531,11 +538,18 @@ void ChipLinuxAppMainLoop(AppMainLoopImplementation * impl) #if defined(ENABLE_CHIP_SHELL) Engine::Root().Init(); + Shell::RegisterCommissioneeCommands(); std::thread shellThread([]() { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + // Unblock SIGINT and SIGTERM, so that the shell thread can handle + // them - we need read() call to be interrupted. + pthread_sigmask(SIG_UNBLOCK, &set, nullptr); Engine::Root().RunMainLoop(); StopMainEventLoop(); }); - Shell::RegisterCommissioneeCommands(); #endif initParams.operationalServicePort = CHIP_PORT; initParams.userDirectedCommissioningPort = CHIP_UDC_PORT; @@ -670,12 +684,22 @@ void ChipLinuxAppMainLoop(AppMainLoopImplementation * impl) ApplicationInit(); -#if !defined(ENABLE_CHIP_SHELL) + // NOTE: For some reason, on Darwin, the signal handler is not called if the signal is + // registered with sigaction() call and TSAN is enabled. The problem seems to be + // related with the dispatch_semaphore_wait() function in the RunEventLoop() method. + // If this call is commented out, the signal handler is called as expected... +#if defined(__APPLE__) // NOLINTBEGIN(bugprone-signal-handler) signal(SIGINT, StopSignalHandler); signal(SIGTERM, StopSignalHandler); // NOLINTEND(bugprone-signal-handler) -#endif // !defined(ENABLE_CHIP_SHELL) +#else + struct sigaction sa = {}; + sa.sa_handler = StopSignalHandler; + sa.sa_flags = SA_RESETHAND; + sigaction(SIGINT, &sa, nullptr); + sigaction(SIGTERM, &sa, nullptr); +#endif if (impl != nullptr) { diff --git a/examples/tv-casting-app/linux/main.cpp b/examples/tv-casting-app/linux/main.cpp index 3a41f15d531c30..11e1c56e9f0d89 100644 --- a/examples/tv-casting-app/linux/main.cpp +++ b/examples/tv-casting-app/linux/main.cpp @@ -16,6 +16,8 @@ * limitations under the License. */ +#include + #include "commands/clusters/SubscriptionsCommands.h" #include "commands/common/Commands.h" #include "commands/example/ExampleCredentialIssuerCommands.h" @@ -105,17 +107,56 @@ CHIP_ERROR ProcessClusterCommand(int argc, char ** argv) return CHIP_NO_ERROR; } +void StopMainEventLoop() +{ + Server::GetInstance().GenerateShutDownEvent(); + DeviceLayer::SystemLayer().ScheduleLambda([]() { DeviceLayer::PlatformMgr().StopEventLoopTask(); }); +} + +void StopSignalHandler(int /* signal */) +{ +#if defined(ENABLE_CHIP_SHELL) + Engine::Root().StopMainLoop(); +#endif + StopMainEventLoop(); +} + int main(int argc, char * argv[]) { - ChipLogProgress(AppServer, "chip_casting_simplified = 0"); // this file is built/run only if chip_casting_simplified = 0 + // This file is built/run only if chip_casting_simplified = 0 + ChipLogProgress(AppServer, "chip_casting_simplified = 0"); + +#if defined(ENABLE_CHIP_SHELL) + /* Block SIGINT and SIGTERM. Other threads created by the main thread + * will inherit the signal mask. Then we can explicitly unblock signals + * in the shell thread to handle them, so the read(stdin) call can be + * interrupted by a signal. */ + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + pthread_sigmask(SIG_BLOCK, &set, nullptr); +#endif + VerifyOrDie(CHIP_NO_ERROR == chip::Platform::MemoryInit()); VerifyOrDie(CHIP_NO_ERROR == chip::DeviceLayer::PlatformMgr().InitChipStack()); #if defined(ENABLE_CHIP_SHELL) Engine::Root().Init(); - std::thread shellThread([]() { Engine::Root().RunMainLoop(); }); Shell::RegisterCastingCommands(); + std::thread shellThread([]() { + sigset_t set_; + sigemptyset(&set_); + sigaddset(&set_, SIGINT); + sigaddset(&set_, SIGTERM); + // Unblock SIGINT and SIGTERM, so that the shell thread can handle + // them - we need read() call to be interrupted. + pthread_sigmask(SIG_UNBLOCK, &set_, nullptr); + Engine::Root().RunMainLoop(); + StopMainEventLoop(); + }); #endif + CHIP_ERROR err = CHIP_NO_ERROR; DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().Init(CHIP_CONFIG_KVS_PATH); @@ -172,11 +213,25 @@ int main(int argc, char * argv[]) ProcessClusterCommand(argc, argv); } + { + struct sigaction sa = {}; + sa.sa_handler = StopSignalHandler; + sa.sa_flags = SA_RESETHAND; + sigaction(SIGINT, &sa, nullptr); + sigaction(SIGTERM, &sa, nullptr); + } + DeviceLayer::PlatformMgr().RunEventLoop(); + exit: + #if defined(ENABLE_CHIP_SHELL) shellThread.join(); #endif + + chip::Server::GetInstance().Shutdown(); + chip::DeviceLayer::PlatformMgr().Shutdown(); + if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "Failed to run TV Casting App: %s", ErrorStr(err)); diff --git a/examples/tv-casting-app/linux/simple-app.cpp b/examples/tv-casting-app/linux/simple-app.cpp index 5526d6a3f6df07..a0863fa9e4e35b 100644 --- a/examples/tv-casting-app/linux/simple-app.cpp +++ b/examples/tv-casting-app/linux/simple-app.cpp @@ -16,6 +16,8 @@ * limitations under the License. */ +#include + #include "simple-app-helper.h" #include "core/CastingPlayer.h" @@ -89,9 +91,37 @@ class CommonCaseDeviceServerInitParamsProvider : public ServerInitParamsProvider } }; +void StopMainEventLoop() +{ + chip::Server::GetInstance().GenerateShutDownEvent(); + chip::DeviceLayer::SystemLayer().ScheduleLambda([]() { chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); }); +} + +void StopSignalHandler(int /* signal */) +{ +#if defined(ENABLE_CHIP_SHELL) + chip::Shell::Engine::Root().StopMainLoop(); +#endif + StopMainEventLoop(); +} + int main(int argc, char * argv[]) { - ChipLogProgress(AppServer, "chip_casting_simplified = 1"); // this file is built/run only if chip_casting_simplified = 1 + // This file is built/run only if chip_casting_simplified = 1 + ChipLogProgress(AppServer, "chip_casting_simplified = 1"); + +#if defined(ENABLE_CHIP_SHELL) + /* Block SIGINT and SIGTERM. Other threads created by the main thread + * will inherit the signal mask. Then we can explicitly unblock signals + * in the shell thread to handle them, so the read(stdin) call can be + * interrupted by a signal. */ + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + pthread_sigmask(SIG_BLOCK, &set, nullptr); +#endif + // Create AppParameters that need to be passed to CastingApp.Initialize() AppParameters appParameters; RotatingDeviceIdUniqueIdProvider rotatingDeviceIdUniqueIdProvider; @@ -122,8 +152,18 @@ int main(int argc, char * argv[]) #if defined(ENABLE_CHIP_SHELL) chip::Shell::Engine::Root().Init(); - std::thread shellThread([]() { chip::Shell::Engine::Root().RunMainLoop(); }); RegisterCommands(); + std::thread shellThread([]() { + sigset_t set_; + sigemptyset(&set_); + sigaddset(&set_, SIGINT); + sigaddset(&set_, SIGTERM); + // Unblock SIGINT and SIGTERM, so that the shell thread can handle + // them - we need read() call to be interrupted. + pthread_sigmask(SIG_UNBLOCK, &set_, nullptr); + chip::Shell::Engine::Root().RunMainLoop(); + StopMainEventLoop(); + }); #endif CastingPlayerDiscovery::GetInstance()->SetDelegate(DiscoveryDelegateImpl::GetInstance()); @@ -133,7 +173,20 @@ int main(int argc, char * argv[]) VerifyOrReturnValue(err == CHIP_NO_ERROR, -1, ChipLogError(AppServer, "CastingPlayerDiscovery::StartDiscovery failed %" CHIP_ERROR_FORMAT, err.Format())); + struct sigaction sa = {}; + sa.sa_handler = StopSignalHandler; + sa.sa_flags = SA_RESETHAND; + sigaction(SIGINT, &sa, nullptr); + sigaction(SIGTERM, &sa, nullptr); + chip::DeviceLayer::PlatformMgr().RunEventLoop(); +#if defined(ENABLE_CHIP_SHELL) + shellThread.join(); +#endif + + chip::Server::GetInstance().Shutdown(); + chip::DeviceLayer::PlatformMgr().Shutdown(); + return 0; } diff --git a/scripts/tests/run_tv_casting_test.py b/scripts/tests/run_tv_casting_test.py index 7b530c7a4a1780..fb02b2ad2f97c7 100755 --- a/scripts/tests/run_tv_casting_test.py +++ b/scripts/tests/run_tv_casting_test.py @@ -17,7 +17,6 @@ import glob import logging import os -import signal import sys import tempfile import time @@ -32,7 +31,7 @@ """ This script can be used to validate the casting experience between the Linux tv-casting-app and the Linux tv-app. -It runs a series of test sequences that check for expected output lines from the tv-casting-app and the tv-app in +It runs a series of test sequences that check for expected output lines from the tv-casting-app and the tv-app in a deterministic order. If these lines are not found, it indicates an issue with the casting experience. """ @@ -92,24 +91,14 @@ def stop_app(test_sequence_name: str, app_name: str, app: ProcessOutputCapture): None, ) - if app_exit_code >= 0: + if app_exit_code != 0: raise TestStepException( f"{test_sequence_name}: {app_name} exited with unexpected exit code {app_exit_code}.", test_sequence_name, None, ) - signal_number = -app_exit_code - if signal_number != signal.SIGTERM.value: - raise TestStepException( - f"{test_sequence_name}: {app_name} stopped by signal {signal_number} instead of {signal.SIGTERM.value} (SIGTERM).", - test_sequence_name, - None, - ) - - logging.info( - f"{test_sequence_name}: {app_name} stopped by {signal_number} (SIGTERM) signal." - ) + logging.info(f"{test_sequence_name}: {app_name} stopped.") def parse_output_msg_in_subprocess( diff --git a/src/lib/shell/Engine.h b/src/lib/shell/Engine.h index a0d7cfa6fa71fe..6307384db60a76 100644 --- a/src/lib/shell/Engine.h +++ b/src/lib/shell/Engine.h @@ -119,6 +119,13 @@ class Engine */ void RunMainLoop(); + /** + * Stop the shell mainloop on the next iteration. + * + * @note This method can be called from a signal handler to stop the main loop. + */ + void StopMainLoop() { mRunning = false; } + /** * Initialize the Shell::Engine. * @@ -130,6 +137,7 @@ class Engine private: static void ProcessShellLineTask(intptr_t context); + bool mRunning = true; }; } // namespace Shell diff --git a/src/lib/shell/MainLoopAmeba.cpp b/src/lib/shell/MainLoopAmeba.cpp index b8476a5dd9a9f0..4f5ea91beca656 100644 --- a/src/lib/shell/MainLoopAmeba.cpp +++ b/src/lib/shell/MainLoopAmeba.cpp @@ -135,7 +135,7 @@ namespace Shell { void Engine::RunMainLoop() { char line[CHIP_SHELL_MAX_LINE_SIZE]; - while (true) + while (mRunning) { memset(line, 0, CHIP_SHELL_MAX_LINE_SIZE); if (ReadLine(line, CHIP_SHELL_MAX_LINE_SIZE) > 0u) diff --git a/src/lib/shell/MainLoopDefault.cpp b/src/lib/shell/MainLoopDefault.cpp index dba76397927f2c..6a3a6b300b53f3 100644 --- a/src/lib/shell/MainLoopDefault.cpp +++ b/src/lib/shell/MainLoopDefault.cpp @@ -15,13 +15,15 @@ * limitations under the License. */ -#include "streamer.h" +#include +#include +#include + #include #include #include -#include -#include +#include "streamer.h" using chip::FormatCHIPError; using chip::Platform::MemoryAlloc; @@ -46,11 +48,18 @@ size_t ReadLine(char * buffer, size_t max) break; } - if (streamer_read(streamer_get(), buffer + line_sz, 1) != 1) + auto ret = streamer_read(streamer_get(), buffer + line_sz, 1); + if (ret == -1 && errno == EINTR) { - continue; + streamer_printf(streamer_get(), "^C\r\n"); + // In case of EINTR (Ctrl-C) reset the buffer and start over. + buffer[line_sz = 0] = '\0'; + break; } + if (ret != 1) + continue; + // Process character we just read. switch (buffer[line_sz]) { @@ -188,7 +197,7 @@ void Engine::RunMainLoop() { streamer_printf(streamer_get(), CHIP_SHELL_PROMPT); - while (true) + while (mRunning) { char * line = static_cast(Platform::MemoryAlloc(CHIP_SHELL_MAX_LINE_SIZE)); if (ReadLine(line, CHIP_SHELL_MAX_LINE_SIZE) == 0u) diff --git a/src/lib/shell/MainLoopESP32.cpp b/src/lib/shell/MainLoopESP32.cpp index aecca35774a07e..1c36a5ccf4fe81 100644 --- a/src/lib/shell/MainLoopESP32.cpp +++ b/src/lib/shell/MainLoopESP32.cpp @@ -70,7 +70,7 @@ namespace Shell { void Engine::RunMainLoop() { - while (true) + while (mRunning) { const char * prompt = LOG_COLOR_I "> " LOG_RESET_COLOR; char * line = linenoise(prompt); diff --git a/src/lib/shell/MainLoopMW320.cpp b/src/lib/shell/MainLoopMW320.cpp index ea7ca5de0a70df..833c87a3bc5e7b 100644 --- a/src/lib/shell/MainLoopMW320.cpp +++ b/src/lib/shell/MainLoopMW320.cpp @@ -273,7 +273,7 @@ void Engine::RunMainLoop() Engine::Root().RegisterDefaultCommands(); RegisterMetaCommands(); - while (true) + while (mRunning) { streamer_printf(streamer_get(), CHIP_SHELL_PROMPT); diff --git a/src/lib/shell/MainLoopSilabs.cpp b/src/lib/shell/MainLoopSilabs.cpp index 8613c48b552f6f..63c9d0ad6f2005 100644 --- a/src/lib/shell/MainLoopSilabs.cpp +++ b/src/lib/shell/MainLoopSilabs.cpp @@ -218,7 +218,7 @@ void Engine::RunMainLoop() { streamer_printf(streamer_get(), kShellPrompt); - while (true) + while (mRunning) { char * line = static_cast(Platform::MemoryAlloc(CHIP_SHELL_MAX_LINE_SIZE)); ReadLine(line, CHIP_SHELL_MAX_LINE_SIZE); From 7c557f6fbe9b1069d1135cb596d8f90e57c190bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20BOU=C3=89?= Date: Thu, 28 Nov 2024 16:11:43 +0100 Subject: [PATCH 16/26] Update light-switch-app/nrfconnect/README.md to fix privilege (#36657) Update light-switch-app/nrfconnect/README.md to fix privilege --- examples/light-switch-app/nrfconnect/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/light-switch-app/nrfconnect/README.md b/examples/light-switch-app/nrfconnect/README.md index 02f7b500aa6270..7869d71bf16a17 100644 --- a/examples/light-switch-app/nrfconnect/README.md +++ b/examples/light-switch-app/nrfconnect/README.md @@ -650,7 +650,7 @@ To perform the unicast binding process, complete the following steps: - `{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233], "targets": null}` is an ACL for the communication with the CHIP Tool. - - `{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [2], "targets": [{"cluster": 6, "endpoint": 1, "deviceType": null}, {"cluster": 8, "endpoint": 1, "deviceType": null}]}` + - `{"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": [2], "targets": [{"cluster": 6, "endpoint": 1, "deviceType": null}, {"cluster": 8, "endpoint": 1, "deviceType": null}]}` is an ACL for binding (cluster no. 6 is the On/Off cluster and the cluster no. 8 is the Level Control cluster). From abc89a739c00a4875c0949b042671b99dd3a0d2c Mon Sep 17 00:00:00 2001 From: Sergio Soares Date: Thu, 28 Nov 2024 10:16:41 -0500 Subject: [PATCH 17/26] python.md: Add real example for run_python_test for the lighting_app (#36645) This PR adds a real example for running the `run_python_test.py` script against the `chip-lighting-app`. --- docs/testing/python.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/testing/python.md b/docs/testing/python.md index 4541871dcba139..26a1dae1f42d5a 100644 --- a/docs/testing/python.md +++ b/docs/testing/python.md @@ -631,6 +631,12 @@ example DUT on the host and includes factory reset support ./scripts/tests/run_python_test.py --factory-reset --app --app-args "whatever" --script --script-args "whatever" ``` +For example, to run TC-ACE-1.2 tests against the linux `chip-lighting-app`: + +```shell +./scripts/tests/run_python_test.py --factory-reset --app ./out/linux-x64-light-no-ble/chip-lighting-app --app-args "--trace-to json:log" --script src/python_testing/TC_ACE_1_2.py --script-args "--commissioning-method on-network --qr-code MT:-24J0AFN00KA0648G00" +``` + # Running tests in CI - Add test to the `repl_tests_linux` section of `.github/workflows/tests.yaml` From 406aca528c61f9834e206313bffca05a093cd115 Mon Sep 17 00:00:00 2001 From: Sergio Soares Date: Thu, 28 Nov 2024 11:27:32 -0500 Subject: [PATCH 18/26] python.md: Fix python_env command (#36641) * python.md: Fix python_env command This PR fixes the python activation command in the tutorial. From `source pyenv/bin/activate` to `source out/python_env/bin/activate` * Restyled by prettier-markdown --------- Co-authored-by: Restyled.io --- docs/testing/python.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/testing/python.md b/docs/testing/python.md index 26a1dae1f42d5a..1db6ff779b8461 100644 --- a/docs/testing/python.md +++ b/docs/testing/python.md @@ -590,12 +590,11 @@ or bootstrap.sh should be used for for the first setup, activate.sh may be used for subsequent setups as it is faster. -Next build the python wheels and create / activate a venv (called `pyenv` here, -but any name may be used) +Next build the python wheels and create / activate a venv ``` ./scripts/build_python.sh -i out/python_env -source pyenv/bin/activate +source out/python_env/bin/activate ``` ## Running tests From 2e09ccc1215e86c183ea7e2c51301af2354cd0cb Mon Sep 17 00:00:00 2001 From: dinabenamar <108664279+dinabenamar@users.noreply.github.com> Date: Thu, 28 Nov 2024 17:28:16 +0100 Subject: [PATCH 19/26] [NXP][platform][RT][RW61x] Disable "chip_inet_config_enable_tcp_endpoint" gn arg (#36665) * [NXP][platform][rt1060] Disable chip_inet_config_enable_tcp_endpoint Signed-off-by: Dina Benamar * [NXP][platform][rt1170] Disable chip_inet_config_enable_tcp_endpoint Signed-off-by: Dina Benamar * [NXP][platform][rw61x] Disable chip_inet_config_enable_tcp_endpoint Signed-off-by: Dina Benamar --------- Signed-off-by: Dina Benamar --- src/platform/nxp/rt/rt1060/args.gni | 3 +++ src/platform/nxp/rt/rt1170/args.gni | 3 +++ src/platform/nxp/rt/rw61x/args.gni | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/platform/nxp/rt/rt1060/args.gni b/src/platform/nxp/rt/rt1060/args.gni index b5fe5340f8ff38..cca2833841f6b3 100644 --- a/src/platform/nxp/rt/rt1060/args.gni +++ b/src/platform/nxp/rt/rt1060/args.gni @@ -32,6 +32,9 @@ chip_ble_project_config_include = "" chip_build_tests = false +# Disable TCP endpoint. +chip_inet_config_enable_tcp_endpoint = false + #This enables the EventList global attribute enable_eventlist_attribute = true diff --git a/src/platform/nxp/rt/rt1170/args.gni b/src/platform/nxp/rt/rt1170/args.gni index aaadc3081a5b4a..9e5fdbdf063fd8 100644 --- a/src/platform/nxp/rt/rt1170/args.gni +++ b/src/platform/nxp/rt/rt1170/args.gni @@ -32,6 +32,9 @@ chip_ble_project_config_include = "" chip_build_tests = false +# Disable TCP endpoint. +chip_inet_config_enable_tcp_endpoint = false + #This enables the EventList global attribute enable_eventlist_attribute = true diff --git a/src/platform/nxp/rt/rw61x/args.gni b/src/platform/nxp/rt/rw61x/args.gni index 543e1a1fe72a4f..e008e7b13adfc9 100644 --- a/src/platform/nxp/rt/rw61x/args.gni +++ b/src/platform/nxp/rt/rw61x/args.gni @@ -34,6 +34,9 @@ chip_ble_project_config_include = "" chip_build_tests = false +# Disable TCP endpoint. +chip_inet_config_enable_tcp_endpoint = false + declare_args() { spinel_interface_rpmsg = true From ddfc5df8d539ed9999d1f79c33472f8734b88b0e Mon Sep 17 00:00:00 2001 From: lucicop Date: Thu, 28 Nov 2024 19:09:30 +0200 Subject: [PATCH 20/26] Add skip_bytes functionality to OTA Provider and BDX downloader class (#36357) --- .../ota-provider-common/BdxOtaSender.cpp | 26 ++++++++++++++----- .../clusters/ota-requestor/BDXDownloader.cpp | 9 +++++++ .../clusters/ota-requestor/BDXDownloader.h | 2 +- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/examples/ota-provider-app/ota-provider-common/BdxOtaSender.cpp b/examples/ota-provider-app/ota-provider-common/BdxOtaSender.cpp index 871d8bfb19de86..12f6e76997fe79 100644 --- a/examples/ota-provider-app/ota-provider-common/BdxOtaSender.cpp +++ b/examples/ota-provider-app/ota-provider-common/BdxOtaSender.cpp @@ -124,16 +124,24 @@ void BdxOtaSender::HandleTransferSessionOutput(TransferSession::OutputEvent & ev break; } - case TransferSession::OutputEventType::kQueryReceived: { + case TransferSession::OutputEventType::kQueryReceived: + case TransferSession::OutputEventType::kQueryWithSkipReceived: { TransferSession::BlockData blockData; uint16_t blockSize = mTransfer.GetTransferBlockSize(); uint16_t bytesToRead = blockSize; + uint64_t bytesToSkip = 0; + + if (event.EventType == TransferSession::OutputEventType::kQueryWithSkipReceived) + { + bytesToSkip = event.bytesToSkip.BytesToSkip; + } + uint64_t seekOffset = mNumBytesSent + bytesToSkip; // TODO: This should be a utility function in TransferSession - if (mTransfer.GetTransferLength() > 0 && mNumBytesSent + blockSize > mTransfer.GetTransferLength()) + if ((mTransfer.GetTransferLength() > 0) && ((seekOffset + blockSize) > mTransfer.GetTransferLength())) { // cast should be safe because of condition above - bytesToRead = static_cast(mTransfer.GetTransferLength() - mNumBytesSent); + bytesToRead = static_cast(mTransfer.GetTransferLength() - seekOffset); } chip::System::PacketBufferHandle blockBuf = chip::System::PacketBufferHandle::New(bytesToRead); @@ -152,7 +160,13 @@ void BdxOtaSender::HandleTransferSessionOutput(TransferSession::OutputEvent & ev return; } - otaFile.seekg(mNumBytesSent); + if (seekOffset > static_cast(std::numeric_limits::max())) + { + ChipLogError(BDX, "Seek offset too large"); + mTransfer.AbortTransfer(StatusCode::kLengthTooLarge); + return; + } + otaFile.seekg(static_cast(seekOffset)); otaFile.read(reinterpret_cast(blockBuf->Start()), bytesToRead); if (!(otaFile.good() || otaFile.eof())) { @@ -164,8 +178,8 @@ void BdxOtaSender::HandleTransferSessionOutput(TransferSession::OutputEvent & ev blockData.Data = blockBuf->Start(); blockData.Length = static_cast(otaFile.gcount()); blockData.IsEof = (blockData.Length < blockSize) || - (mNumBytesSent + static_cast(blockData.Length) == mTransfer.GetTransferLength() || (otaFile.peek() == EOF)); - mNumBytesSent = static_cast(mNumBytesSent + blockData.Length); + (seekOffset + static_cast(blockData.Length) == mTransfer.GetTransferLength() || (otaFile.peek() == EOF)); + mNumBytesSent = static_cast(seekOffset + blockData.Length); otaFile.close(); err = mTransfer.PrepareBlock(blockData); diff --git a/src/app/clusters/ota-requestor/BDXDownloader.cpp b/src/app/clusters/ota-requestor/BDXDownloader.cpp index 9c17cf0dde2228..43e3efca4af647 100644 --- a/src/app/clusters/ota-requestor/BDXDownloader.cpp +++ b/src/app/clusters/ota-requestor/BDXDownloader.cpp @@ -159,6 +159,15 @@ CHIP_ERROR BDXDownloader::FetchNextData() return CHIP_NO_ERROR; } +CHIP_ERROR BDXDownloader::SkipData(uint32_t numBytes) +{ + VerifyOrReturnError(mState == State::kInProgress, CHIP_ERROR_INCORRECT_STATE); + ReturnErrorOnFailure(mBdxTransfer.PrepareBlockQueryWithSkip(numBytes)); + PollTransferSession(); + + return CHIP_NO_ERROR; +} + void BDXDownloader::OnDownloadTimeout() { Reset(); diff --git a/src/app/clusters/ota-requestor/BDXDownloader.h b/src/app/clusters/ota-requestor/BDXDownloader.h index 121b59c027a704..69d1e8cc020a89 100644 --- a/src/app/clusters/ota-requestor/BDXDownloader.h +++ b/src/app/clusters/ota-requestor/BDXDownloader.h @@ -73,7 +73,7 @@ class BDXDownloader : public chip::OTADownloader // instead. void EndDownload(CHIP_ERROR reason = CHIP_NO_ERROR) override; CHIP_ERROR FetchNextData() override; - // TODO: override SkipData + CHIP_ERROR SkipData(uint32_t numBytes) override; System::Clock::Timeout GetTimeout(); // If True, there's been a timeout in the transfer as measured by no download progress after 'mTimeout' seconds. From a39c1787f083a829268055e333afd5cb73b0f971 Mon Sep 17 00:00:00 2001 From: Ricardo Casallas <77841255+rcasallas-silabs@users.noreply.github.com> Date: Thu, 28 Nov 2024 13:27:11 -0500 Subject: [PATCH 21/26] [Silabs] Trustzone-compatibility. (#36643) --- .../silabs/efr32/CHIPCryptoPALPsaEfr32.cpp | 308 +++++++----------- .../silabs/efr32/OTAImageProcessorImpl.cpp | 4 + .../silabs/platformAbstraction/GsdkSpam.cpp | 12 +- 3 files changed, 139 insertions(+), 185 deletions(-) diff --git a/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp b/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp index fc926ab5a8e5c5..0f3405d34cc950 100644 --- a/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp +++ b/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp @@ -43,12 +43,6 @@ #include "psa/crypto.h" -// Go straight for the driver wrappers for speed on plaintext keys -extern "C" { -#include "psa_crypto_core.h" -#include "psa_crypto_driver_wrappers.h" -} - // Includes needed for SPAKE2+ ECP operations #include #include @@ -439,139 +433,79 @@ CHIP_ERROR HKDF_sha::HKDF_SHA256(const uint8_t * secret, const size_t secret_len CHIP_ERROR HMAC_sha::HMAC_SHA256(const uint8_t * key, size_t key_length, const uint8_t * message, size_t message_length, uint8_t * out_buffer, size_t out_length) { - VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(key_length > 0, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(message != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(message_length > 0, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(out_length >= kSHA256_Hash_Length, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(out_buffer != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; - size_t output_length = 0; + VerifyOrReturnError(IsBufferNonEmpty(key, key_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsBufferNonEmpty(message, message_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(out_buffer != nullptr && out_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), CHIP_ERROR_INVALID_ARGUMENT); - psa_crypto_init(); + const psa_algorithm_t algorithm = PSA_ALG_HMAC(PSA_ALG_SHA_256); + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_SUCCESS; + psa_key_attributes_t attrs = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t keyId = 0; - psa_set_key_type(&attr, PSA_KEY_TYPE_HMAC); - psa_set_key_bits(&attr, key_length * 8); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_HASH); - psa_set_key_algorithm(&attr, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + psa_set_key_type(&attrs, PSA_KEY_TYPE_HMAC); + psa_set_key_algorithm(&attrs, algorithm); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_SIGN_HASH); - status = psa_driver_wrapper_mac_compute(&attr, Uint8::to_const_uchar(key), key_length, PSA_ALG_HMAC(PSA_ALG_SHA_256), - Uint8::to_const_uchar(message), message_length, out_buffer, out_length, &output_length); + status = psa_import_key(&attrs, key, key_length, &keyId); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + status = psa_mac_compute(keyId, algorithm, message, message_length, out_buffer, out_length, &out_length); VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), error = CHIP_ERROR_INTERNAL); + exit: - psa_mac_abort(&operation); - psa_reset_key_attributes(&attr); - return error; + LogPsaError(status); + psa_destroy_key(keyId); + psa_reset_key_attributes(&attrs); + + return CHIP_NO_ERROR; } CHIP_ERROR HMAC_sha::HMAC_SHA256(const Hmac128KeyHandle & key, const uint8_t * message, size_t message_length, uint8_t * out_buffer, size_t out_length) { - return HMAC_SHA256(key.As(), sizeof(Symmetric128BitsKeyByteArray), message, message_length, - out_buffer, out_length); -} - -CHIP_ERROR PBKDF2_sha256::pbkdf2_sha256(const uint8_t * password, size_t plen, const uint8_t * salt, size_t slen, - unsigned int iteration_count, uint32_t key_length, uint8_t * output) -{ - // TODO: replace inlined algorithm with usage of the PSA key derivation API once implemented - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - size_t output_length = 0; - - // Align these buffers on the native data size to speed up the XOR - static const size_t hash_size_in_native = - ((PSA_HASH_LENGTH(PSA_ALG_SHA_256) + sizeof(unsigned int) - 1) / sizeof(unsigned int)); - static_assert(hash_size_in_native * sizeof(unsigned int) >= PSA_HASH_LENGTH(PSA_ALG_SHA_256)); - - unsigned int md1_buffer[hash_size_in_native]; - unsigned int work_buffer[hash_size_in_native]; - uint8_t * md1 = (uint8_t *) md1_buffer; - uint8_t * work = (uint8_t *) work_buffer; - - size_t use_len; - unsigned char * out_p = output; - uint8_t * U1 = (uint8_t *) MemoryCalloc(1, slen + 4); - - VerifyOrExit(U1 != nullptr, error = CHIP_ERROR_NO_MEMORY); - VerifyOrExit(password != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(plen > 0, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(salt != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(slen >= kSpake2p_Min_PBKDF_Salt_Length, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(slen <= kSpake2p_Max_PBKDF_Salt_Length, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(key_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(output != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsBufferNonEmpty(message, message_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(out_buffer != nullptr && out_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), CHIP_ERROR_INVALID_ARGUMENT); - psa_crypto_init(); - - psa_set_key_type(&attr, PSA_KEY_TYPE_HMAC); - psa_set_key_bits(&attr, plen * 8); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_HASH); - psa_set_key_algorithm(&attr, PSA_ALG_HMAC(PSA_ALG_SHA_256)); - - // Start with initializing the salt + counter - memcpy(U1, salt, slen); - U1[slen] = 0; - U1[slen + 1] = 0; - U1[slen + 2] = 0; - U1[slen + 3] = 1; - - // Loop until we have generated the requested key length - while (key_length) - { - // U1 ends up in work - status = psa_driver_wrapper_mac_compute(&attr, password, plen, PSA_ALG_HMAC(PSA_ALG_SHA_256), U1, slen + 4, work, - PSA_HASH_LENGTH(PSA_ALG_SHA_256), &output_length); + const psa_algorithm_t algorithm = PSA_ALG_HMAC(PSA_ALG_SHA_256); + psa_status_t status = PSA_SUCCESS; - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), error = CHIP_ERROR_INTERNAL); + status = psa_mac_compute(key.As(), algorithm, message, message_length, out_buffer, out_length, &out_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - memcpy(md1, work, PSA_HASH_LENGTH(PSA_ALG_SHA_256)); + return CHIP_NO_ERROR; +} - for (size_t i = 1; i < iteration_count; i++) - { - // U2 ends up in md1 - // +CHIP_ERROR PBKDF2_sha256::pbkdf2_sha256(const uint8_t * password, size_t pass_length, const uint8_t * salt, size_t salt_length, + unsigned int iteration_count, uint32_t key_length, uint8_t * key) +{ + VerifyOrReturnError(IsBufferNonEmpty(password, pass_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(salt_length >= kSpake2p_Min_PBKDF_Salt_Length && salt_length <= kSpake2p_Max_PBKDF_Salt_Length, + CHIP_ERROR_INVALID_ARGUMENT); - status = psa_driver_wrapper_mac_compute(&attr, password, plen, PSA_ALG_HMAC(PSA_ALG_SHA_256), md1, sizeof(md1_buffer), - md1, sizeof(md1_buffer), &output_length); + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_SUCCESS; + psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == PSA_HASH_LENGTH(PSA_ALG_SHA_256), error = CHIP_ERROR_INTERNAL); + status = psa_key_derivation_setup(&operation, PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256)); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - // U1 xor U2 - // - for (size_t j = 0; j < hash_size_in_native; j++) - { - work_buffer[j] ^= md1_buffer[j]; - } - } + status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SALT, salt, salt_length); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - use_len = (key_length < PSA_HASH_LENGTH(PSA_ALG_SHA_256)) ? key_length : PSA_HASH_LENGTH(PSA_ALG_SHA_256); - memcpy(out_p, work, use_len); + status = psa_key_derivation_input_integer(&operation, PSA_KEY_DERIVATION_INPUT_COST, iteration_count); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - key_length -= (uint32_t) use_len; - out_p += use_len; + status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_PASSWORD, password, pass_length); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - for (size_t i = 4; i > 0; i--) - { - if (++U1[slen + i - 1] != 0) - { - break; - } - } - } + status = psa_key_derivation_output_bytes(&operation, key, key_length); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); exit: - MemoryFree(U1); - psa_reset_key_attributes(&attr); + psa_key_derivation_abort(&operation); + return error; } @@ -656,62 +590,50 @@ static inline const psa_plaintext_ecp_keypair * to_const_keypair(const P256Keypa CHIP_ERROR P256Keypair::ECDSA_sign_msg(const uint8_t * msg, const size_t msg_length, P256ECDSASignature & out_signature) const { - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - size_t output_length = 0; - const psa_plaintext_ecp_keypair * keypair = to_const_keypair(&mKeypair); - - VerifyOrExit(mInitialized, error = CHIP_ERROR_UNINITIALIZED); - VerifyOrExit((msg != nullptr) && (msg_length > 0), error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(mInitialized, CHIP_ERROR_UNINITIALIZED); + VerifyOrReturnError(IsBufferNonEmpty(msg, msg_length), CHIP_ERROR_INVALID_ARGUMENT); - psa_crypto_init(); + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_SUCCESS; + size_t outputLen = 0; + const PsaP256KeypairContext & context = ToConstPsaContext(mKeypair); - psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); - psa_set_key_bits(&attr, keypair->bitlen); - psa_set_key_algorithm(&attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_SIGN_MESSAGE); + status = psa_sign_message(context.key_id, PSA_ALG_ECDSA(PSA_ALG_SHA_256), msg, msg_length, out_signature.Bytes(), + out_signature.Capacity(), &outputLen); - // use imported key to sign a message - status = - psa_driver_wrapper_sign_message(&attr, keypair->privkey, PSA_BITS_TO_BYTES(keypair->bitlen), PSA_ALG_ECDSA(PSA_ALG_SHA_256), - msg, msg_length, out_signature.Bytes(), out_signature.Capacity(), &output_length); - - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - VerifyOrReturnError(output_length == kP256_ECDSA_Signature_Length_Raw, CHIP_ERROR_INTERNAL); - VerifyOrReturnError(out_signature.SetLength(output_length) == CHIP_NO_ERROR, CHIP_ERROR_INTERNAL); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + VerifyOrExit(outputLen == kP256_ECDSA_Signature_Length_Raw, error = CHIP_ERROR_INTERNAL); + error = out_signature.SetLength(outputLen); exit: - _log_PSA_error(status); - psa_reset_key_attributes(&attr); - + LogPsaError(status); return error; } CHIP_ERROR P256PublicKey::ECDSA_validate_msg_signature(const uint8_t * msg, const size_t msg_length, const P256ECDSASignature & signature) const { - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - - VerifyOrExit((msg != nullptr) && (msg_length > 0), error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsBufferNonEmpty(msg, msg_length), CHIP_ERROR_INVALID_ARGUMENT); - psa_crypto_init(); + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_SUCCESS; + psa_key_id_t keyId = 0; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); - psa_set_key_bits(&attr, 256); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_VERIFY_MESSAGE); - psa_set_key_algorithm(&attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_MESSAGE); - // use imported key to verify a message - status = psa_driver_wrapper_verify_message(&attr, Uint8::to_const_uchar(*this), Length(), PSA_ALG_ECDSA(PSA_ALG_SHA_256), msg, - msg_length, signature.ConstBytes(), signature.Length()); + status = psa_import_key(&attributes, ConstBytes(), Length(), &keyId); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + status = psa_verify_message(keyId, PSA_ALG_ECDSA(PSA_ALG_SHA_256), msg, msg_length, signature.ConstBytes(), signature.Length()); VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INVALID_SIGNATURE); + exit: - _log_PSA_error(status); - psa_reset_key_attributes(&attr); + LogPsaError(status); + psa_destroy_key(keyId); + psa_reset_key_attributes(&attributes); return error; } @@ -719,30 +641,29 @@ CHIP_ERROR P256PublicKey::ECDSA_validate_msg_signature(const uint8_t * msg, cons CHIP_ERROR P256PublicKey::ECDSA_validate_hash_signature(const uint8_t * hash, const size_t hash_length, const P256ECDSASignature & signature) const { - VerifyOrReturnError(hash != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(hash_length == kSHA256_Hash_Length, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(hash != nullptr && hash_length == kSHA256_Hash_Length, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(signature.Length() == kP256_ECDSA_Signature_Length_Raw, CHIP_ERROR_INVALID_ARGUMENT); - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - - // Step 1: import public key as volatile - psa_crypto_init(); + CHIP_ERROR error = CHIP_NO_ERROR; + psa_status_t status = PSA_SUCCESS; + psa_key_id_t keyId = 0; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); - psa_set_key_bits(&attr, 256); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_VERIFY_HASH); - psa_set_key_algorithm(&attr, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); + psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256)); - // use imported key to verify a hash - status = psa_driver_wrapper_verify_hash(&attr, Uint8::to_const_uchar(*this), Length(), PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, - hash_length, signature.ConstBytes(), signature.Length()); + status = psa_import_key(&attributes, ConstBytes(), Length(), &keyId); + VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); + status = psa_verify_hash(keyId, PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, hash_length, signature.ConstBytes(), signature.Length()); VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INVALID_SIGNATURE); + exit: - _log_PSA_error(status); - psa_reset_key_attributes(&attr); + LogPsaError(status); + psa_destroy_key(keyId); + psa_reset_key_attributes(&attributes); + return error; } @@ -1204,20 +1125,43 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointWrite(const void * R, uint8_t * o return CHIP_NO_ERROR; } -extern "C" { -#include "em_device.h" -} - #if defined(SEMAILBOX_PRESENT) // Add inlined optimisation which can use the SE to do point multiplication operations using // the ECDH primitive as a proxy for scalar multiplication. extern "C" { #include "sl_se_manager.h" #include "sl_se_manager_key_derivation.h" -#include "sl_se_manager_util.h" -#include "sli_se_driver_key_management.h" -#include "sli_se_manager_internal.h" } + +/** Pad size to word alignment + * Copied from: + * ${simplicity_sdk}/platform/security/sl_component/sl_psa_driver/inc/sli_se_driver_key_management.h + * @param size + * Unsigend integer type. + * @returns the number of padding bytes required + */ +#define sli_se_word_align(size) ((size + 3) & ~3) + +/** + * @brief + * Set the key desc to a plaintext key type pointing to data. + * Copied from: + * ${simplicity_sdk}/platform/security/sl_component/sl_psa_driver/inc/sli_se_driver_key_management.h + * @param[out] key_desc + * The SE manager key struct representing a key + * @param[in] data + * Buffer containing the key + * @param[in] data_length + * Length of the buffer + */ +static inline void key_descriptor_set_plaintext(sl_se_key_descriptor_t * key_desc, const uint8_t * data, size_t data_length) +{ + key_desc->storage.method = SL_SE_KEY_STORAGE_EXTERNAL_PLAINTEXT; + key_desc->storage.location.buffer.pointer = (uint8_t *) data; + // TODO: Improve SE manager alignment requirements + key_desc->storage.location.buffer.size = sli_se_word_align(data_length); +} + #endif /* SEMAILBOX_PRESENT */ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointMul(void * R, const void * P1, const void * fe1) @@ -1265,17 +1209,17 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointMul(void * R, const void * P1, co // Set private key to scalar priv_desc.type = SL_SE_KEY_TYPE_ECC_P256; priv_desc.flags |= SL_SE_KEY_FLAG_ASYMMETRIC_BUFFER_HAS_PRIVATE_KEY; - sli_se_key_descriptor_set_plaintext(&priv_desc, scalar, sizeof(scalar)); + key_descriptor_set_plaintext(&priv_desc, scalar, sizeof(scalar)); // Set public key to point pub_desc.type = SL_SE_KEY_TYPE_ECC_P256; pub_desc.flags |= SL_SE_KEY_FLAG_ASYMMETRIC_BUFFER_HAS_PUBLIC_KEY; - sli_se_key_descriptor_set_plaintext(&pub_desc, point, sizeof(point)); + key_descriptor_set_plaintext(&pub_desc, point, sizeof(point)); // Set output to point shared_desc.type = SL_SE_KEY_TYPE_SYMMETRIC; shared_desc.size = sizeof(point); - sli_se_key_descriptor_set_plaintext(&shared_desc, point, sizeof(point)); + key_descriptor_set_plaintext(&shared_desc, point, sizeof(point)); // Re-init SE command context. sl_status = sl_se_init_command_context(&cmd_ctx); diff --git a/src/platform/silabs/efr32/OTAImageProcessorImpl.cpp b/src/platform/silabs/efr32/OTAImageProcessorImpl.cpp index 09d37d0ca7380d..3699b36041a350 100644 --- a/src/platform/silabs/efr32/OTAImageProcessorImpl.cpp +++ b/src/platform/silabs/efr32/OTAImageProcessorImpl.cpp @@ -224,7 +224,11 @@ void OTAImageProcessorImpl::HandleApply(intptr_t context) return; } #endif // SL_BTLCTRL_MUX +#if defined(SL_TRUSTZONE_NONSECURE) + CORE_CRITICAL_SECTION(err = bootloader_verifyImage(mSlotId);) +#else CORE_CRITICAL_SECTION(err = bootloader_verifyImage(mSlotId, NULL);) +#endif if (err != SL_BOOTLOADER_OK) { ChipLogError(SoftwareUpdate, "bootloader_verifyImage() error: %ld", err); diff --git a/src/platform/silabs/platformAbstraction/GsdkSpam.cpp b/src/platform/silabs/platformAbstraction/GsdkSpam.cpp index 361dfa93a44aa2..bc221ead6ad870 100644 --- a/src/platform/silabs/platformAbstraction/GsdkSpam.cpp +++ b/src/platform/silabs/platformAbstraction/GsdkSpam.cpp @@ -126,7 +126,9 @@ CHIP_ERROR SilabsPlatform::Init(void) CHIP_ERROR SilabsPlatform::FlashInit() { -#if defined(_SILICON_LABS_32B_SERIES_2) +#if defined(SL_TRUSTZONE_NONSECURE) + return CHIP_ERROR_NOT_IMPLEMENTED; +#elif defined(_SILICON_LABS_32B_SERIES_2) MSC_Init(); #elif defined(_SILICON_LABS_32B_SERIES_3) sl_status_t status; @@ -140,7 +142,9 @@ CHIP_ERROR SilabsPlatform::FlashInit() CHIP_ERROR SilabsPlatform::FlashErasePage(uint32_t addr) { -#if defined(_SILICON_LABS_32B_SERIES_2) +#if defined(SL_TRUSTZONE_NONSECURE) + return CHIP_ERROR_NOT_IMPLEMENTED; +#elif defined(_SILICON_LABS_32B_SERIES_2) MSC_ErasePage((uint32_t *) addr); #elif defined(_SILICON_LABS_32B_SERIES_3) sl_status_t status; @@ -158,7 +162,9 @@ CHIP_ERROR SilabsPlatform::FlashErasePage(uint32_t addr) CHIP_ERROR SilabsPlatform::FlashWritePage(uint32_t addr, const uint8_t * data, size_t size) { -#if defined(_SILICON_LABS_32B_SERIES_2) +#if defined(SL_TRUSTZONE_NONSECURE) + return CHIP_ERROR_NOT_IMPLEMENTED; +#elif defined(_SILICON_LABS_32B_SERIES_2) MSC_WriteWord((uint32_t *) addr, data, size); #elif defined(_SILICON_LABS_32B_SERIES_3) sl_status_t status; From 439de24a545754ef4357c724310eaac7497134a2 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Thu, 28 Nov 2024 14:08:02 -0500 Subject: [PATCH 22/26] [Silabs] Silabs Uart Shell fixes (#36667) * [SL-UP] Bugfix/silabs out rtt removal (#142) * [SL-UP] Bugfix/matter shell crash nullptr (#125) * Added checks on null ptr to prevent uart shell crash and modified ICD shell commands to be compatible with our internal structure --- examples/platform/silabs/shell/BUILD.gn | 10 +++++----- .../silabs/shell/{ => icd}/ICDShellCommands.cpp | 0 .../silabs/shell/{ => icd}/ICDShellCommands.h | 0 src/lib/shell/Engine.cpp | 2 ++ src/platform/silabs/Logging.cpp | 13 ++++--------- third_party/silabs/SiWx917_sdk.gni | 7 +++---- third_party/silabs/efr32_sdk.gni | 7 +++---- 7 files changed, 17 insertions(+), 22 deletions(-) rename examples/platform/silabs/shell/{ => icd}/ICDShellCommands.cpp (100%) rename examples/platform/silabs/shell/{ => icd}/ICDShellCommands.h (100%) diff --git a/examples/platform/silabs/shell/BUILD.gn b/examples/platform/silabs/shell/BUILD.gn index 74613aeac91031..8d4cab328e71dc 100644 --- a/examples/platform/silabs/shell/BUILD.gn +++ b/examples/platform/silabs/shell/BUILD.gn @@ -23,17 +23,17 @@ if (use_SiWx917) { shell_dependency_path = "${chip_root}/examples/platform/silabs/SiWx917" } -config("shell-config") { - include_dirs = [ "." ] +config("icd-shell-config") { + include_dirs = [ "./icd/" ] } source_set("icd") { sources = [ - "ICDShellCommands.cpp", - "ICDShellCommands.h", + "./icd/ICDShellCommands.cpp", + "./icd/ICDShellCommands.h", ] - public_configs = [ ":shell-config" ] + public_configs = [ ":icd-shell-config" ] deps = [ "${shell_dependency_path}:matter-shell" ] } diff --git a/examples/platform/silabs/shell/ICDShellCommands.cpp b/examples/platform/silabs/shell/icd/ICDShellCommands.cpp similarity index 100% rename from examples/platform/silabs/shell/ICDShellCommands.cpp rename to examples/platform/silabs/shell/icd/ICDShellCommands.cpp diff --git a/examples/platform/silabs/shell/ICDShellCommands.h b/examples/platform/silabs/shell/icd/ICDShellCommands.h similarity index 100% rename from examples/platform/silabs/shell/ICDShellCommands.h rename to examples/platform/silabs/shell/icd/ICDShellCommands.h diff --git a/src/lib/shell/Engine.cpp b/src/lib/shell/Engine.cpp index 809d44cc3c2bd4..ac914012819d66 100644 --- a/src/lib/shell/Engine.cpp +++ b/src/lib/shell/Engine.cpp @@ -86,6 +86,8 @@ CHIP_ERROR Engine::ExecCommand(int argc, char * argv[]) CHIP_ERROR retval = CHIP_ERROR_INVALID_ARGUMENT; VerifyOrReturnError(argc > 0, retval); + VerifyOrReturnError(nullptr != argv, retval); + // Find the command for (unsigned i = 0; i < _commandSetCount; i++) { diff --git a/src/platform/silabs/Logging.cpp b/src/platform/silabs/Logging.cpp index dea891379140fa..8b34308ba02f7e 100644 --- a/src/platform/silabs/Logging.cpp +++ b/src/platform/silabs/Logging.cpp @@ -51,13 +51,8 @@ #include "uart.h" #endif -// Enable RTT by default -#ifndef SILABS_LOG_OUT_RTT -#define SILABS_LOG_OUT_RTT 1 -#endif - // SEGGER_RTT includes -#if SILABS_LOG_OUT_RTT +#if !SILABS_LOG_OUT_UART #include "SEGGER_RTT.h" #include "SEGGER_RTT_Conf.h" #endif @@ -136,7 +131,7 @@ static void PrintLog(const char * msg) SEGGER_RTT_WriteNoLock(LOG_RTT_BUFFER_INDEX, msg, sz); #endif // SILABS_LOG_OUT_UART -#if SILABS_LOG_OUT_RTT || PW_RPC_ENABLED +#if !SILABS_LOG_OUT_UART || PW_RPC_ENABLED const char * newline = "\r\n"; sz = strlen(newline); #if PW_RPC_ENABLED @@ -154,7 +149,7 @@ static void PrintLog(const char * msg) extern "C" void silabsInitLog(void) { #if SILABS_LOG_ENABLED -#if SILABS_LOG_OUT_RTT +#if !SILABS_LOG_OUT_UART #if LOG_RTT_BUFFER_INDEX != 0 SEGGER_RTT_ConfigUpBuffer(LOG_RTT_BUFFER_INDEX, LOG_RTT_BUFFER_NAME, sLogBuffer, LOG_RTT_BUFFER_SIZE, SEGGER_RTT_MODE_NO_BLOCK_TRIM); @@ -164,7 +159,7 @@ extern "C" void silabsInitLog(void) #else SEGGER_RTT_SetFlagsUpBuffer(LOG_RTT_BUFFER_INDEX, SEGGER_RTT_MODE_NO_BLOCK_TRIM); #endif -#endif // SILABS_LOG_OUT_RTT +#endif // !SILABS_LOG_OUT_UART #ifdef PW_RPC_ENABLED PigweedLogger::init(); diff --git a/third_party/silabs/SiWx917_sdk.gni b/third_party/silabs/SiWx917_sdk.gni index 0bc8c7c69318c4..63a0add4c4a5e9 100644 --- a/third_party/silabs/SiWx917_sdk.gni +++ b/third_party/silabs/SiWx917_sdk.gni @@ -331,10 +331,9 @@ template("siwx917_sdk") { } if (sl_uart_log_output) { - defines += [ - "SILABS_LOG_OUT_UART=1", - "SILABS_LOG_OUT_RTT=0", - ] + defines += [ "SILABS_LOG_OUT_UART=1" ] + } else { + defines += [ "SILABS_LOG_OUT_UART=0" ] } if (chip_build_libshell) { # matter shell diff --git a/third_party/silabs/efr32_sdk.gni b/third_party/silabs/efr32_sdk.gni index 7861e827d7bdfb..bb621e0dce84b5 100644 --- a/third_party/silabs/efr32_sdk.gni +++ b/third_party/silabs/efr32_sdk.gni @@ -487,10 +487,9 @@ template("efr32_sdk") { } if (sl_uart_log_output) { - defines += [ - "SILABS_LOG_OUT_UART=1", - "SILABS_LOG_OUT_RTT=0", - ] + defines += [ "SILABS_LOG_OUT_UART=1" ] + } else { + defines += [ "SILABS_LOG_OUT_UART=0" ] } if (use_silabs_thread_lib) { From 1805b3ecad8c516f5f2b6a678bf0cdf29877c449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20BOU=C3=89?= Date: Fri, 29 Nov 2024 01:41:08 +0100 Subject: [PATCH 23/26] Update energy-management-app README.md (#36662) * Update energy-management-app README.md Add link to `kBasicInstallationTestEvent` definition * Update README.md * Update README.md * Restyle * Update README.md Use commit it --- examples/energy-management-app/linux/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/energy-management-app/linux/README.md b/examples/energy-management-app/linux/README.md index 637b80f95de8f0..9bb1cd3820f0a0 100644 --- a/examples/energy-management-app/linux/README.md +++ b/examples/energy-management-app/linux/README.md @@ -595,8 +595,9 @@ Step-by-step: 1. Set the default TestEventTrigger (`0x0094000000000000`): -- `0x0094000000000000` corresponds to `kBasicInstallationTestEvent` from - `WaterHeadermanagementTestEventTriggerHandler.h` +- `0x0094000000000000` corresponds to + [`kBasicInstallationTestEvent`](https://github.com/project-chip/connectedhomeip/blob/5e3127f5ac61e13c572a968199280d90a9c19dce/src/app/clusters/water-heater-management-server/WaterHeaterManagementTestEventTriggerHandler.h#L47) + from `WaterHeadermanagementTestEventTriggerHandler.h` - `hex:00010203...0e0f` is the `--enable-key` passed to the startup of chip-energy-management-app - `0x12344321` is the node-id that the app was commissioned on From b3e074c96e2a72fa427dbb1827ffa717ea97a6ac Mon Sep 17 00:00:00 2001 From: Mathieu Kardous <84793247+mkardous-silabs@users.noreply.github.com> Date: Fri, 29 Nov 2024 00:50:44 -0500 Subject: [PATCH 24/26] Remove Active flag when the readhandler is going to be destroyed (#36653) * remove Active flag when the readhandler is going to be destroyed * Restyled by clang-format --------- Co-authored-by: Restyled.io --- src/app/ReadHandler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/ReadHandler.cpp b/src/app/ReadHandler.cpp index 4794ead97eb86b..43f9b9310df848 100644 --- a/src/app/ReadHandler.cpp +++ b/src/app/ReadHandler.cpp @@ -152,6 +152,7 @@ ReadHandler::~ReadHandler() auto * appCallback = mManagementCallback.GetAppCallback(); if (mFlags.Has(ReadHandlerFlags::ActiveSubscription) && appCallback) { + mFlags.Clear(ReadHandlerFlags::ActiveSubscription); appCallback->OnSubscriptionTerminated(*this); } From 19cbdf498bd5cd207f90ad5b7ff48b4151d1db97 Mon Sep 17 00:00:00 2001 From: crlonxp <88241281+crlonxp@users.noreply.github.com> Date: Fri, 29 Nov 2024 15:28:03 +0800 Subject: [PATCH 25/26] Sync latest commits of the laundry-washer-app in nxp rw61x platform (#36664) * Fix Matter 1.3 certifiction TC-LWM-1.1 case that feature-map should be 0 Signed-off-by: Chin-Ran Lo (cherry picked from commit 21c40394dd0df65b1dd07e6cf9545f9d5cb1af25) * Update laundry washer ZAP file to pass TC-IDM-10.2/10.4/10.5 during Matter 1.4 SVE Signed-off-by: Oliver Fan [nxp toup][laundry-washer-app][common] Update laundry washer to pass TC-OPSTATE-2.6 during Matter 1.4 SVE Signed-off-by: Oliver Fan [nxp toup][laundry-washer-app][RW612][RTOS] Update RW612 RTOS laundry washer app to pass TC-OPSTATE-2.6 during Matter 1.4 SVE Signed-off-by: Oliver Fan [nxp toup][laundry-washer-app][RT1170][RTOS] Update RT1170+IW612 RTOS laundry washer app to pass TC-OPSTATE-2.6 during Matter 1.4 SVE Signed-off-by: Oliver Fan [nxp toup][laundry-washer-app][RW612][Zephyr] Update laundry washer to pass TC-OPSTATE-2.6, TC-IDM-10.2/10.4/10.5 during Matter 1.4 SVE Signed-off-by: Oliver Fan * Update RW/RT device types ZAP files to align with latest root node configuration updates done in thermostat zap configuration Signed-off-by: Lo,Chin-Ran * Update RT1060 RTOS laundry washer app to aligh with rw61x and rt1170 to pass TC-OPSTATE-2.6 Signed-off-by: Oliver Fan * Restyled by clang-format * Restyled by gn --------- Signed-off-by: Oliver Fan Signed-off-by: Lo,Chin-Ran Co-authored-by: Chin-Ran Lo Co-authored-by: Oliver Fan Co-authored-by: Restyled.io --- .../nxp/common/main/AppTask.cpp | 12 +- .../include/operational-state-delegate-impl.h | 120 - .../main/operational-state-delegate-impl.cpp | 142 - .../laundry-washer-app/nxp/rt/rt1060/BUILD.gn | 23 +- .../laundry-washer-app/nxp/rt/rt1170/BUILD.gn | 23 +- .../laundry-washer-app/nxp/rt/rw61x/BUILD.gn | 25 +- .../nxp/zap/laundry-washer-app.matter | 526 ++-- .../nxp/zap/laundry-washer-app.zap | 2340 +++++++++-------- .../nxp/zephyr/CMakeLists.txt | 5 +- 9 files changed, 1510 insertions(+), 1706 deletions(-) delete mode 100644 examples/laundry-washer-app/nxp/common/main/include/operational-state-delegate-impl.h delete mode 100644 examples/laundry-washer-app/nxp/common/main/operational-state-delegate-impl.cpp diff --git a/examples/laundry-washer-app/nxp/common/main/AppTask.cpp b/examples/laundry-washer-app/nxp/common/main/AppTask.cpp index 5d82dcf92ef7b3..b9cb8716dbe776 100644 --- a/examples/laundry-washer-app/nxp/common/main/AppTask.cpp +++ b/examples/laundry-washer-app/nxp/common/main/AppTask.cpp @@ -22,6 +22,7 @@ #include "CHIPDeviceManager.h" #include "ICDUtil.h" #include +#include #include #include "static-supported-temperature-levels.h" @@ -85,8 +86,15 @@ static CHIP_ERROR cliOpState(int argc, char * argv[]) if (map_cmd_opstate.find(argv[0]) != map_cmd_opstate.end()) { - OperationalState::GetOperationalStateInstance()->SetOperationalState(map_cmd_opstate.at(argv[0])); - ChipLogDetail(Shell, "OpSState : Set to %s state", argv[0]); + auto error = OperationalState::GetOperationalStateInstance()->SetOperationalState(map_cmd_opstate.at(argv[0])); + ChipLogDetail(Shell, "OpSState : Set to %s state & CountdownTime", argv[0]); + if ((error == CHIP_NO_ERROR) && + (map_cmd_opstate.at(argv[0]) == to_underlying(chip::app::Clusters::OperationalState::OperationalStateEnum::kRunning))) + { + chip::app::Clusters::OperationalState::GenericOperationalError err( + to_underlying(chip::app::Clusters::OperationalState::ErrorStateEnum::kNoError)); + OperationalState::GetOperationalStateDelegate()->HandleStartStateCallback(err); + } if (!strcmp(argv[0], "error") && argc == 2) { OperationalState::Structs::ErrorStateStruct::Type err; diff --git a/examples/laundry-washer-app/nxp/common/main/include/operational-state-delegate-impl.h b/examples/laundry-washer-app/nxp/common/main/include/operational-state-delegate-impl.h deleted file mode 100644 index 79f2695eb0a628..00000000000000 --- a/examples/laundry-washer-app/nxp/common/main/include/operational-state-delegate-impl.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * - * 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: - /** - * Get the countdown time. This attribute is not used in this application. - * @return The current countdown time. - */ - app::DataModel::Nullable GetCountdownTime() override { return {}; }; - - /** - * 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)), - }; - -public: - OperationalStateDelegate() - { - GenericOperationalStateDelegateImpl::mOperationalStateList = Span(opStateList); - } -}; - -Instance * GetOperationalStateInstance(); - -void Shutdown(); - -} // namespace OperationalState -} // namespace Clusters -} // namespace app -} // namespace chip diff --git a/examples/laundry-washer-app/nxp/common/main/operational-state-delegate-impl.cpp b/examples/laundry-washer-app/nxp/common/main/operational-state-delegate-impl.cpp deleted file mode 100644 index 961fc868ed12b5..00000000000000 --- a/examples/laundry-washer-app/nxp/common/main/operational-state-delegate-impl.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - * - * 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 - -using namespace chip; -using namespace chip::app; -using namespace chip::app::Clusters; -using namespace chip::app::Clusters::OperationalState; - -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) -{ - // 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) -{ - // 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) -{ - uint8_t opState = GetInstance()->GetCurrentOperationalState(); - if (opState == to_underlying(OperationalStateEnum::kError)) - { - err.Set(to_underlying(ErrorStateEnum::kUnableToStartOrResume)); - 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::HandleStopStateCallback(GenericOperationalError & err) -{ - // placeholder implementation - auto error = GetInstance()->SetOperationalState(to_underlying(OperationalStateEnum::kStopped)); - if (error == CHIP_NO_ERROR) - { - err.Set(to_underlying(ErrorStateEnum::kNoError)); - } - else - { - err.Set(to_underlying(ErrorStateEnum::kUnableToCompleteOperation)); - } -} - -// 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/laundry-washer-app/nxp/rt/rt1060/BUILD.gn b/examples/laundry-washer-app/nxp/rt/rt1060/BUILD.gn index ee1e896987ae9b..4e417419464ee8 100644 --- a/examples/laundry-washer-app/nxp/rt/rt1060/BUILD.gn +++ b/examples/laundry-washer-app/nxp/rt/rt1060/BUILD.gn @@ -44,6 +44,8 @@ declare_args() { # Setup discriminator as argument setup_discriminator = 3840 + + chip_with_diag_logs_demo = true } example_platform_dir = @@ -116,6 +118,13 @@ rt_executable("laundry-washer") { defines += [ "CONFIG_NET_L2_OPENTHREAD=1" ] } + if (chip_with_diag_logs_demo) { + defines += [ + "CONFIG_DIAG_LOGS_DEMO=1", + "CHIP_DEVICE_CONFIG_MAX_DIAG_LOG_SIZE=1024", + ] + } + include_dirs = [ "../../common/main/include", "../../common/main", @@ -135,6 +144,17 @@ rt_executable("laundry-washer") { "../../common/main/main.cpp", ] + if (chip_with_diag_logs_demo) { + include_dirs += [ + "${common_example_dir}/diagnostic_logs/include", + "${chip_root}", + ] + sources += [ + "${common_example_dir}/diagnostic_logs/source/DiagnosticLogsDemo.cpp", + "${common_example_dir}/diagnostic_logs/source/DiagnosticLogsProviderDelegateImpl.cpp", + ] + } + # App common files include_dirs += [ "${common_example_dir}/icd/include", @@ -163,11 +183,10 @@ rt_executable("laundry-washer") { sources += [ "${chip_root}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/laundry-washer-controls-delegate-impl.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/operational-state-delegate-impl.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/smco-stub.cpp", - "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", "../../common/main/laundry-washer-mode.cpp", - "../../common/main/operational-state-delegate-impl.cpp", ] if (nxp_enable_matter_cli) { diff --git a/examples/laundry-washer-app/nxp/rt/rt1170/BUILD.gn b/examples/laundry-washer-app/nxp/rt/rt1170/BUILD.gn index 90be59719a193d..0e0e71e8c2dfc1 100644 --- a/examples/laundry-washer-app/nxp/rt/rt1170/BUILD.gn +++ b/examples/laundry-washer-app/nxp/rt/rt1170/BUILD.gn @@ -41,6 +41,8 @@ declare_args() { # Setup discriminator as argument setup_discriminator = 3840 + + chip_with_diag_logs_demo = true } example_platform_dir = @@ -106,6 +108,13 @@ rt_executable("laundry-washer-app") { defines += [ "CONFIG_NET_L2_OPENTHREAD=1" ] } + if (chip_with_diag_logs_demo) { + defines += [ + "CONFIG_DIAG_LOGS_DEMO=1", + "CHIP_DEVICE_CONFIG_MAX_DIAG_LOG_SIZE=1024", + ] + } + include_dirs = [ "../../common/main/include", "../../common/main", @@ -125,6 +134,17 @@ rt_executable("laundry-washer-app") { "../../common/main/main.cpp", ] + if (chip_with_diag_logs_demo) { + include_dirs += [ + "${common_example_dir}/diagnostic_logs/include", + "${chip_root}", + ] + sources += [ + "${common_example_dir}/diagnostic_logs/source/DiagnosticLogsDemo.cpp", + "${common_example_dir}/diagnostic_logs/source/DiagnosticLogsProviderDelegateImpl.cpp", + ] + } + # App common files include_dirs += [ "${common_example_dir}/icd/include", @@ -151,11 +171,10 @@ rt_executable("laundry-washer-app") { sources += [ "${chip_root}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/laundry-washer-controls-delegate-impl.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/operational-state-delegate-impl.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/smco-stub.cpp", - "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", "../../common/main/laundry-washer-mode.cpp", - "../../common/main/operational-state-delegate-impl.cpp", ] if (nxp_enable_matter_cli) { diff --git a/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn b/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn index 063cf49b81a2b5..1ef89a3852c2d9 100644 --- a/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn +++ b/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn @@ -1,5 +1,5 @@ # Copyright (c) 2021 Project CHIP Authors -# Copyright 2023 NXP +# Copyright 2023-2024 NXP # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -42,6 +42,8 @@ declare_args() { # Setup discriminator as argument setup_discriminator = 3840 + + chip_with_diag_logs_demo = true } example_platform_dir = @@ -114,6 +116,13 @@ rt_executable("laundry-washer") { defines += [ "CONFIG_NET_L2_OPENTHREAD=1" ] } + if (chip_with_diag_logs_demo) { + defines += [ + "CONFIG_DIAG_LOGS_DEMO=1", + "CHIP_DEVICE_CONFIG_MAX_DIAG_LOG_SIZE=1024", + ] + } + include_dirs = [ "../../common/main/include", "../../common/main", @@ -133,6 +142,17 @@ rt_executable("laundry-washer") { "../../common/main/main.cpp", ] + if (chip_with_diag_logs_demo) { + include_dirs += [ + "${common_example_dir}/diagnostic_logs/include", + "${chip_root}", + ] + sources += [ + "${common_example_dir}/diagnostic_logs/source/DiagnosticLogsDemo.cpp", + "${common_example_dir}/diagnostic_logs/source/DiagnosticLogsProviderDelegateImpl.cpp", + ] + } + if (nxp_enable_secure_whole_factory_data || nxp_enable_secure_EL2GO_factory_data) { sources += [ "${chip_root}/examples/platform/nxp/${nxp_platform}/factory_data/source/AppFactoryDataExample.cpp" ] @@ -173,11 +193,10 @@ rt_executable("laundry-washer") { sources += [ "${chip_root}/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/laundry-washer-controls-delegate-impl.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/operational-state-delegate-impl.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/smco-stub.cpp", - "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-modes-manager.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/static-supported-temperature-levels.cpp", "../../common/main/laundry-washer-mode.cpp", - "../../common/main/operational-state-delegate-impl.cpp", ] if (nxp_enable_matter_cli) { diff --git a/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter b/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter index 28a2f46d284903..37b7786af95b80 100644 --- a/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter +++ b/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter @@ -870,6 +870,23 @@ cluster OtaSoftwareUpdateRequestor = 42 { command AnnounceOTAProvider(AnnounceOTAProviderRequest): DefaultSuccess = 0; } +/** Nodes should be expected to be deployed to any and all regions of the world. These global regions + may have differing common languages, units of measurements, and numerical formatting + standards. As such, Nodes that visually or audibly convey information need a mechanism by which + they can be configured to use a user’s preferred language, units, etc */ +cluster LocalizationConfiguration = 43 { + revision 1; // NOTE: Default/not specifically set + + attribute access(write: manage) char_string<35> activeLocale = 0; + readonly attribute char_string supportedLocales[] = 1; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + /** Nodes should be expected to be deployed to any and all regions of the world. These global regions may have differing preferences for the units in which values are conveyed in communication to a user. As such, Nodes that visually or audibly convey measurable values to the user need a @@ -896,265 +913,6 @@ cluster UnitLocalization = 45 { readonly attribute int16u clusterRevision = 65533; } -/** This cluster is used to describe the configuration and capabilities of a physical power source that provides power to the Node. */ -cluster PowerSource = 47 { - revision 1; // NOTE: Default/not specifically set - - enum BatApprovedChemistryEnum : enum16 { - kUnspecified = 0; - kAlkaline = 1; - kLithiumCarbonFluoride = 2; - kLithiumChromiumOxide = 3; - kLithiumCopperOxide = 4; - kLithiumIronDisulfide = 5; - kLithiumManganeseDioxide = 6; - kLithiumThionylChloride = 7; - kMagnesium = 8; - kMercuryOxide = 9; - kNickelOxyhydride = 10; - kSilverOxide = 11; - kZincAir = 12; - kZincCarbon = 13; - kZincChloride = 14; - kZincManganeseDioxide = 15; - kLeadAcid = 16; - kLithiumCobaltOxide = 17; - kLithiumIon = 18; - kLithiumIonPolymer = 19; - kLithiumIronPhosphate = 20; - kLithiumSulfur = 21; - kLithiumTitanate = 22; - kNickelCadmium = 23; - kNickelHydrogen = 24; - kNickelIron = 25; - kNickelMetalHydride = 26; - kNickelZinc = 27; - kSilverZinc = 28; - kSodiumIon = 29; - kSodiumSulfur = 30; - kZincBromide = 31; - kZincCerium = 32; - } - - enum BatChargeFaultEnum : enum8 { - kUnspecified = 0; - kAmbientTooHot = 1; - kAmbientTooCold = 2; - kBatteryTooHot = 3; - kBatteryTooCold = 4; - kBatteryAbsent = 5; - kBatteryOverVoltage = 6; - kBatteryUnderVoltage = 7; - kChargerOverVoltage = 8; - kChargerUnderVoltage = 9; - kSafetyTimeout = 10; - } - - enum BatChargeLevelEnum : enum8 { - kOK = 0; - kWarning = 1; - kCritical = 2; - } - - enum BatChargeStateEnum : enum8 { - kUnknown = 0; - kIsCharging = 1; - kIsAtFullCharge = 2; - kIsNotCharging = 3; - } - - enum BatCommonDesignationEnum : enum16 { - kUnspecified = 0; - kAAA = 1; - kAA = 2; - kC = 3; - kD = 4; - k4v5 = 5; - k6v0 = 6; - k9v0 = 7; - k12AA = 8; - kAAAA = 9; - kA = 10; - kB = 11; - kF = 12; - kN = 13; - kNo6 = 14; - kSubC = 15; - kA23 = 16; - kA27 = 17; - kBA5800 = 18; - kDuplex = 19; - k4SR44 = 20; - k523 = 21; - k531 = 22; - k15v0 = 23; - k22v5 = 24; - k30v0 = 25; - k45v0 = 26; - k67v5 = 27; - kJ = 28; - kCR123A = 29; - kCR2 = 30; - k2CR5 = 31; - kCRP2 = 32; - kCRV3 = 33; - kSR41 = 34; - kSR43 = 35; - kSR44 = 36; - kSR45 = 37; - kSR48 = 38; - kSR54 = 39; - kSR55 = 40; - kSR57 = 41; - kSR58 = 42; - kSR59 = 43; - kSR60 = 44; - kSR63 = 45; - kSR64 = 46; - kSR65 = 47; - kSR66 = 48; - kSR67 = 49; - kSR68 = 50; - kSR69 = 51; - kSR516 = 52; - kSR731 = 53; - kSR712 = 54; - kLR932 = 55; - kA5 = 56; - kA10 = 57; - kA13 = 58; - kA312 = 59; - kA675 = 60; - kAC41E = 61; - k10180 = 62; - k10280 = 63; - k10440 = 64; - k14250 = 65; - k14430 = 66; - k14500 = 67; - k14650 = 68; - k15270 = 69; - k16340 = 70; - kRCR123A = 71; - k17500 = 72; - k17670 = 73; - k18350 = 74; - k18500 = 75; - k18650 = 76; - k19670 = 77; - k25500 = 78; - k26650 = 79; - k32600 = 80; - } - - enum BatFaultEnum : enum8 { - kUnspecified = 0; - kOverTemp = 1; - kUnderTemp = 2; - } - - enum BatReplaceabilityEnum : enum8 { - kUnspecified = 0; - kNotReplaceable = 1; - kUserReplaceable = 2; - kFactoryReplaceable = 3; - } - - enum PowerSourceStatusEnum : enum8 { - kUnspecified = 0; - kActive = 1; - kStandby = 2; - kUnavailable = 3; - } - - enum WiredCurrentTypeEnum : enum8 { - kAC = 0; - kDC = 1; - } - - enum WiredFaultEnum : enum8 { - kUnspecified = 0; - kOverVoltage = 1; - kUnderVoltage = 2; - } - - bitmap Feature : bitmap32 { - kWired = 0x1; - kBattery = 0x2; - kRechargeable = 0x4; - kReplaceable = 0x8; - } - - struct BatChargeFaultChangeType { - BatChargeFaultEnum current[] = 0; - BatChargeFaultEnum previous[] = 1; - } - - struct BatFaultChangeType { - BatFaultEnum current[] = 0; - BatFaultEnum previous[] = 1; - } - - struct WiredFaultChangeType { - WiredFaultEnum current[] = 0; - WiredFaultEnum previous[] = 1; - } - - info event WiredFaultChange = 0 { - WiredFaultEnum current[] = 0; - WiredFaultEnum previous[] = 1; - } - - info event BatFaultChange = 1 { - BatFaultEnum current[] = 0; - BatFaultEnum previous[] = 1; - } - - info event BatChargeFaultChange = 2 { - BatChargeFaultEnum current[] = 0; - BatChargeFaultEnum previous[] = 1; - } - - readonly attribute PowerSourceStatusEnum status = 0; - readonly attribute int8u order = 1; - readonly attribute char_string<60> description = 2; - readonly attribute optional nullable int32u wiredAssessedInputVoltage = 3; - readonly attribute optional nullable int16u wiredAssessedInputFrequency = 4; - readonly attribute optional WiredCurrentTypeEnum wiredCurrentType = 5; - readonly attribute optional nullable int32u wiredAssessedCurrent = 6; - readonly attribute optional int32u wiredNominalVoltage = 7; - readonly attribute optional int32u wiredMaximumCurrent = 8; - readonly attribute optional boolean wiredPresent = 9; - readonly attribute optional WiredFaultEnum activeWiredFaults[] = 10; - readonly attribute optional nullable int32u batVoltage = 11; - readonly attribute optional nullable int8u batPercentRemaining = 12; - readonly attribute optional nullable int32u batTimeRemaining = 13; - readonly attribute optional BatChargeLevelEnum batChargeLevel = 14; - readonly attribute optional boolean batReplacementNeeded = 15; - readonly attribute optional BatReplaceabilityEnum batReplaceability = 16; - readonly attribute optional boolean batPresent = 17; - readonly attribute optional BatFaultEnum activeBatFaults[] = 18; - readonly attribute optional char_string<60> batReplacementDescription = 19; - readonly attribute optional BatCommonDesignationEnum batCommonDesignation = 20; - readonly attribute optional char_string<20> batANSIDesignation = 21; - readonly attribute optional char_string<20> batIECDesignation = 22; - readonly attribute optional BatApprovedChemistryEnum batApprovedChemistry = 23; - readonly attribute optional int32u batCapacity = 24; - readonly attribute optional int8u batQuantity = 25; - readonly attribute optional BatChargeStateEnum batChargeState = 26; - readonly attribute optional nullable int32u batTimeToFullCharge = 27; - readonly attribute optional boolean batFunctionalWhileCharging = 28; - readonly attribute optional nullable int32u batChargingCurrent = 29; - readonly attribute optional BatChargeFaultEnum activeBatChargeFaults[] = 30; - readonly attribute endpoint_no endpointList[] = 31; - readonly attribute command_id generatedCommandList[] = 65528; - readonly attribute command_id acceptedCommandList[] = 65529; - readonly attribute event_id eventList[] = 65530; - readonly attribute attrib_id attributeList[] = 65531; - readonly attribute bitmap32 featureMap = 65532; - readonly attribute int16u clusterRevision = 65533; -} - /** This cluster is used to manage global aspects of the Commissioning flow. */ cluster GeneralCommissioning = 48 { revision 1; // NOTE: Default/not specifically set @@ -1427,6 +1185,53 @@ cluster NetworkCommissioning = 49 { command access(invoke: administer) QueryIdentity(QueryIdentityRequest): QueryIdentityResponse = 9; } +/** The cluster provides commands for retrieving unstructured diagnostic logs from a Node that may be used to aid in diagnostics. */ +cluster DiagnosticLogs = 50 { + revision 1; // NOTE: Default/not specifically set + + enum IntentEnum : enum8 { + kEndUserSupport = 0; + kNetworkDiag = 1; + kCrashLogs = 2; + } + + enum StatusEnum : enum8 { + kSuccess = 0; + kExhausted = 1; + kNoLogs = 2; + kBusy = 3; + kDenied = 4; + } + + enum TransferProtocolEnum : enum8 { + kResponsePayload = 0; + kBDX = 1; + } + + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct RetrieveLogsRequestRequest { + IntentEnum intent = 0; + TransferProtocolEnum requestedProtocol = 1; + optional char_string<32> transferFileDesignator = 2; + } + + response struct RetrieveLogsResponse = 1 { + StatusEnum status = 0; + long_octet_string logContent = 1; + optional epoch_us UTCTimeStamp = 2; + optional systime_us timeSinceBoot = 3; + } + + /** Retrieving diagnostic logs from a Node */ + command RetrieveLogsRequest(RetrieveLogsRequestRequest): RetrieveLogsResponse = 0; +} + /** The General Diagnostics Cluster, along with other diagnostics clusters, provide a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ cluster GeneralDiagnostics = 51 { revision 2; @@ -1558,6 +1363,43 @@ cluster GeneralDiagnostics = 51 { command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; } +/** The Software Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ +cluster SoftwareDiagnostics = 52 { + revision 1; // NOTE: Default/not specifically set + + bitmap Feature : bitmap32 { + kWatermarks = 0x1; + } + + struct ThreadMetricsStruct { + int64u id = 0; + optional char_string<8> name = 1; + optional int32u stackFreeCurrent = 2; + optional int32u stackFreeMinimum = 3; + optional int32u stackSize = 4; + } + + info event SoftwareFault = 0 { + int64u id = 0; + optional char_string name = 1; + optional octet_string faultRecording = 2; + } + + readonly attribute optional ThreadMetricsStruct threadMetrics[] = 0; + readonly attribute optional int64u currentHeapFree = 1; + readonly attribute optional int64u currentHeapUsed = 2; + readonly attribute optional int64u currentHeapHighWatermark = 3; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + /** Reception of this command SHALL reset the values: The StackFreeMinimum field of the ThreadMetrics attribute, CurrentHeapHighWaterMark attribute. */ + command access(invoke: manage) ResetWatermarks(): DefaultSuccess = 0; +} + /** The Wi-Fi Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ cluster WiFiNetworkDiagnostics = 54 { revision 1; // NOTE: Default/not specifically set @@ -1926,46 +1768,6 @@ cluster UserLabel = 65 { readonly attribute int16u clusterRevision = 65533; } -/** Attributes and commands for selecting a mode from a list of supported options. */ -cluster ModeSelect = 80 { - revision 2; - - bitmap Feature : bitmap32 { - kOnOff = 0x1; - } - - struct SemanticTagStruct { - vendor_id mfgCode = 0; - enum16 value = 1; - } - - struct ModeOptionStruct { - char_string<64> label = 0; - int8u mode = 1; - SemanticTagStruct semanticTags[] = 2; - } - - readonly attribute char_string<64> description = 0; - readonly attribute nullable enum16 standardNamespace = 1; - readonly attribute ModeOptionStruct supportedModes[] = 2; - readonly attribute int8u currentMode = 3; - attribute optional nullable int8u startUpMode = 4; - attribute optional nullable int8u onMode = 5; - readonly attribute command_id generatedCommandList[] = 65528; - readonly attribute command_id acceptedCommandList[] = 65529; - readonly attribute event_id eventList[] = 65530; - readonly attribute attrib_id attributeList[] = 65531; - readonly attribute bitmap32 featureMap = 65532; - readonly attribute int16u clusterRevision = 65533; - - request struct ChangeToModeRequest { - int8u newMode = 0; - } - - /** On receipt of this command, if the NewMode field matches the Mode field in an entry of the SupportedModes list, the server SHALL set the CurrentMode attribute to the NewMode value, otherwise, the server SHALL respond with an INVALID_COMMAND status response. */ - command ChangeToMode(ChangeToModeRequest): DefaultSuccess = 0; -} - /** Attributes and commands for selecting a mode from a list of supported options. */ cluster LaundryWasherMode = 81 { revision 2; @@ -2154,7 +1956,8 @@ cluster OperationalState = 96 { } endpoint 0 { - device type ma_rootdevice = 22, version 1; + device type ma_rootdevice = 22, version 0; + device type ma_otarequestor = 18, version 1; binding cluster OtaSoftwareUpdateProvider; @@ -2163,6 +1966,9 @@ endpoint 0 { callback attribute serverList; callback attribute clientList; callback attribute partsList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; callback attribute featureMap; callback attribute clusterRevision; } @@ -2171,10 +1977,11 @@ endpoint 0 { emits event AccessControlEntryChanged; emits event AccessControlExtensionChanged; callback attribute acl; - callback attribute extension; callback attribute subjectsPerAccessControlEntry; callback attribute targetsPerAccessControlEntry; callback attribute accessControlEntriesPerFabric; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; callback attribute attributeList; ram attribute featureMap default = 0; callback attribute clusterRevision; @@ -2182,28 +1989,19 @@ endpoint 0 { server cluster BasicInformation { emits event StartUp; - emits event ShutDown; - emits event Leave; callback attribute dataModelRevision; callback attribute vendorName; callback attribute vendorID; callback attribute productName; callback attribute productID; - persist attribute nodeLabel; + ram attribute nodeLabel; callback attribute location; callback attribute hardwareVersion; callback attribute hardwareVersionString; callback attribute softwareVersion; callback attribute softwareVersionString; - callback attribute manufacturingDate; - callback attribute partNumber; - callback attribute productURL; - callback attribute productLabel; - callback attribute serialNumber; - persist attribute localConfigDisabled default = 0; callback attribute uniqueID; callback attribute capabilityMinima; - callback attribute productAppearance; callback attribute specificationVersion; callback attribute maxPathsPerInvoke; callback attribute generatedCommandList; @@ -2230,7 +2028,9 @@ endpoint 0 { handle command AnnounceOTAProvider; } - server cluster UnitLocalization { + server cluster LocalizationConfiguration { + ram attribute activeLocale; + callback attribute supportedLocales; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute attributeList; @@ -2238,14 +2038,26 @@ endpoint 0 { ram attribute clusterRevision default = 1; } + server cluster UnitLocalization { + ram attribute temperatureUnit; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 1; + ram attribute clusterRevision default = 1; + } + server cluster GeneralCommissioning { ram attribute breadcrumb default = 0x0000000000000000; callback attribute basicCommissioningInfo; callback attribute regulatoryConfig; callback attribute locationCapability; callback attribute supportsConcurrentConnection; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; ram attribute featureMap default = 0; - ram attribute clusterRevision default = 1; + ram attribute clusterRevision default = 2; handle command ArmFailSafe; handle command ArmFailSafeResponse; @@ -2264,11 +2076,12 @@ endpoint 0 { ram attribute lastNetworkingStatus; ram attribute lastNetworkID; ram attribute lastConnectErrorValue; + callback attribute supportedWiFiBands; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute attributeList; ram attribute featureMap default = 2; - ram attribute clusterRevision default = 1; + ram attribute clusterRevision default = 3; handle command ScanNetworks; handle command ScanNetworksResponse; @@ -2281,6 +2094,17 @@ endpoint 0 { handle command ReorderNetwork; } + server cluster DiagnosticLogs { + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command RetrieveLogsRequest; + handle command RetrieveLogsResponse; + } + server cluster GeneralDiagnostics { emits event BootReason; callback attribute networkInterfaces; @@ -2300,24 +2124,53 @@ endpoint 0 { handle command TimeSnapshotResponse; } + server cluster SoftwareDiagnostics { + callback attribute threadMetrics; + callback attribute currentHeapFree; + callback attribute currentHeapUsed; + callback attribute currentHeapHighWatermark; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 1; + + handle command ResetWatermarks; + } + server cluster WiFiNetworkDiagnostics { + emits event Disconnection; + emits event AssociationFailure; + emits event ConnectionStatus; callback attribute bssid; callback attribute securityType; callback attribute wiFiVersion; callback attribute channelNumber; callback attribute rssi; + callback attribute beaconLostCount; + callback attribute beaconRxCount; + callback attribute packetMulticastRxCount; + callback attribute packetMulticastTxCount; + callback attribute packetUnicastRxCount; + callback attribute packetUnicastTxCount; callback attribute currentMaxRate; + callback attribute overrunCount; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute attributeList; - ram attribute featureMap default = 0; + ram attribute featureMap default = 3; ram attribute clusterRevision default = 1; + + handle command ResetCounts; } server cluster AdministratorCommissioning { callback attribute windowStatus; callback attribute adminFabricIndex; callback attribute adminVendorId; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; ram attribute featureMap default = 0; ram attribute clusterRevision default = 1; @@ -2332,6 +2185,9 @@ endpoint 0 { callback attribute commissionedFabrics; callback attribute trustedRootCertificates; callback attribute currentFabricIndex; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; ram attribute featureMap default = 0; ram attribute clusterRevision default = 1; @@ -2354,6 +2210,9 @@ endpoint 0 { callback attribute groupTable; callback attribute maxGroupsPerFabric; callback attribute maxGroupKeysPerFabric; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; callback attribute featureMap; callback attribute clusterRevision; @@ -2411,8 +2270,8 @@ endpoint 1 { callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute attributeList; - ram attribute featureMap default = 1; - ram attribute clusterRevision default = 5; + ram attribute featureMap default = 2; + ram attribute clusterRevision default = 6; handle command Off; handle command On; @@ -2443,19 +2302,6 @@ endpoint 1 { ram attribute clusterRevision default = 1; } - server cluster PowerSource { - ram attribute status; - ram attribute order; - ram attribute description; - ram attribute wiredCurrentType; - callback attribute endpointList; - callback attribute generatedCommandList; - callback attribute acceptedCommandList; - callback attribute attributeList; - ram attribute featureMap default = 1; - ram attribute clusterRevision default = 2; - } - server cluster FixedLabel { callback attribute labelList; callback attribute generatedCommandList; @@ -2474,22 +2320,6 @@ endpoint 1 { ram attribute clusterRevision default = 1; } - server cluster ModeSelect { - ram attribute description; - ram attribute standardNamespace; - callback attribute supportedModes; - ram attribute currentMode; - ram attribute startUpMode; - ram attribute onMode; - callback attribute generatedCommandList; - callback attribute acceptedCommandList; - callback attribute attributeList; - ram attribute featureMap default = 0; - ram attribute clusterRevision default = 1; - - handle command ChangeToMode; - } - server cluster LaundryWasherMode { callback attribute supportedModes; callback attribute currentMode; @@ -2499,7 +2329,7 @@ endpoint 1 { callback attribute acceptedCommandList; callback attribute attributeList; callback attribute featureMap; - ram attribute clusterRevision default = 1; + ram attribute clusterRevision default = 2; handle command ChangeToMode; handle command ChangeToModeResponse; @@ -2542,7 +2372,7 @@ endpoint 1 { callback attribute acceptedCommandList; callback attribute attributeList; ram attribute featureMap default = 0; - ram attribute clusterRevision default = 1; + ram attribute clusterRevision default = 2; handle command Pause; handle command Stop; diff --git a/examples/laundry-washer-app/nxp/zap/laundry-washer-app.zap b/examples/laundry-washer-app/nxp/zap/laundry-washer-app.zap index 8af4eaa8976040..9a8d968d15c421 100644 --- a/examples/laundry-washer-app/nxp/zap/laundry-washer-app.zap +++ b/examples/laundry-washer-app/nxp/zap/laundry-washer-app.zap @@ -1,6 +1,6 @@ { "fileFormat": 2, - "featureLevel": 103, + "featureLevel": 104, "creator": "zap", "keyValuePairs": [ { @@ -38,27 +38,38 @@ "id": 1, "name": "MA-rootdevice", "deviceTypeRef": { - "code": 22, + "code": 18, "profileId": 259, - "label": "MA-rootdevice", - "name": "MA-rootdevice" + "label": "MA-otarequestor", + "name": "MA-otarequestor", + "deviceTypeOrder": 0 }, "deviceTypes": [ + { + "code": 18, + "profileId": 259, + "label": "MA-otarequestor", + "name": "MA-otarequestor", + "deviceTypeOrder": 0 + }, { "code": 22, "profileId": 259, "label": "MA-rootdevice", - "name": "MA-rootdevice" + "name": "MA-rootdevice", + "deviceTypeOrder": 1 } ], "deviceVersions": [ - 1 + 1, + 0 ], "deviceIdentifiers": [ + 18, 22 ], - "deviceTypeName": "MA-rootdevice", - "deviceTypeCode": 22, + "deviceTypeName": "MA-otarequestor", + "deviceTypeCode": 18, "deviceTypeProfileId": 259, "clusters": [ { @@ -133,6 +144,54 @@ "maxInterval": 65344, "reportableChange": 0 }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "FeatureMap", "code": 65532, @@ -192,11 +251,11 @@ "reportableChange": 0 }, { - "name": "Extension", - "code": 1, + "name": "SubjectsPerAccessControlEntry", + "code": 2, "mfgCode": null, "side": "server", - "type": "array", + "type": "int16u", "included": 1, "storageOption": "External", "singleton": 0, @@ -208,8 +267,8 @@ "reportableChange": 0 }, { - "name": "SubjectsPerAccessControlEntry", - "code": 2, + "name": "TargetsPerAccessControlEntry", + "code": 3, "mfgCode": null, "side": "server", "type": "int16u", @@ -224,8 +283,8 @@ "reportableChange": 0 }, { - "name": "TargetsPerAccessControlEntry", - "code": 3, + "name": "AccessControlEntriesPerFabric", + "code": 4, "mfgCode": null, "side": "server", "type": "int16u", @@ -240,11 +299,27 @@ "reportableChange": 0 }, { - "name": "AccessControlEntriesPerFabric", - "code": 4, + "name": "GeneratedCommandList", + "code": 65528, "mfgCode": null, "side": "server", - "type": "int16u", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", "included": 1, "storageOption": "External", "singleton": 0, @@ -416,7 +491,7 @@ "side": "server", "type": "char_string", "included": 1, - "storageOption": "NVM", + "storageOption": "RAM", "singleton": 1, "bounded": 0, "defaultValue": "", @@ -501,104 +576,8 @@ "bounded": 0, "defaultValue": null, "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - }, - { - "name": "ManufacturingDate", - "code": 11, - "mfgCode": null, - "side": "server", - "type": "char_string", - "included": 1, - "storageOption": "External", - "singleton": 1, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - }, - { - "name": "PartNumber", - "code": 12, - "mfgCode": null, - "side": "server", - "type": "char_string", - "included": 1, - "storageOption": "External", - "singleton": 1, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - }, - { - "name": "ProductURL", - "code": 13, - "mfgCode": null, - "side": "server", - "type": "long_char_string", - "included": 1, - "storageOption": "External", - "singleton": 1, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - }, - { - "name": "ProductLabel", - "code": 14, - "mfgCode": null, - "side": "server", - "type": "char_string", - "included": 1, - "storageOption": "External", - "singleton": 1, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - }, - { - "name": "SerialNumber", - "code": 15, - "mfgCode": null, - "side": "server", - "type": "char_string", - "included": 1, - "storageOption": "External", - "singleton": 1, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - }, - { - "name": "LocalConfigDisabled", - "code": 16, - "mfgCode": null, - "side": "server", - "type": "boolean", - "included": 1, - "storageOption": "NVM", - "singleton": 1, - "bounded": 0, - "defaultValue": "0", - "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, + "minInterval": 1, + "maxInterval": 65534, "reportableChange": 0 }, { @@ -625,22 +604,6 @@ "type": "CapabilityMinimaStruct", "included": 1, "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "ProductAppearance", - "code": 20, - "mfgCode": null, - "side": "server", - "type": "ProductAppearanceStruct", - "included": 1, - "storageOption": "External", "singleton": 1, "bounded": 0, "defaultValue": null, @@ -713,22 +676,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 1, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -785,20 +732,6 @@ "mfgCode": null, "side": "server", "included": 1 - }, - { - "name": "ShutDown", - "code": 1, - "mfgCode": null, - "side": "server", - "included": 1 - }, - { - "name": "Leave", - "code": 2, - "mfgCode": null, - "side": "server", - "included": 1 } ] }, @@ -966,22 +899,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -1056,32 +973,32 @@ ] }, { - "name": "Unit Localization", - "code": 45, + "name": "Localization Configuration", + "code": 43, "mfgCode": null, - "define": "UNIT_LOCALIZATION_CLUSTER", + "define": "LOCALIZATION_CONFIGURATION_CLUSTER", "side": "server", "enabled": 1, "attributes": [ { - "name": "GeneratedCommandList", - "code": 65528, + "name": "ActiveLocale", + "code": 0, "mfgCode": null, "side": "server", - "type": "array", + "type": "char_string", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "AcceptedCommandList", - "code": 65529, + "name": "SupportedLocales", + "code": 1, "mfgCode": null, "side": "server", "type": "array", @@ -1096,8 +1013,8 @@ "reportableChange": 0 }, { - "name": "EventList", - "code": 65530, + "name": "GeneratedCommandList", + "code": 65528, "mfgCode": null, "side": "server", "type": "array", @@ -1112,8 +1029,24 @@ "reportableChange": 0 }, { - "name": "AttributeList", - "code": 65531, + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, "mfgCode": null, "side": "server", "type": "array", @@ -1161,6 +1094,112 @@ } ] }, + { + "name": "Unit Localization", + "code": 45, + "mfgCode": null, + "define": "UNIT_LOCALIZATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "TemperatureUnit", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "TempUnitEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, { "name": "General Commissioning", "code": 48, @@ -1299,6 +1338,54 @@ "maxInterval": 65534, "reportableChange": 0 }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "FeatureMap", "code": 65532, @@ -1325,7 +1412,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "1", + "defaultValue": "2", "reportable": 1, "minInterval": 0, "maxInterval": 65344, @@ -1544,8 +1631,8 @@ "reportableChange": 0 }, { - "name": "GeneratedCommandList", - "code": 65528, + "name": "SupportedWiFiBands", + "code": 8, "mfgCode": null, "side": "server", "type": "array", @@ -1560,8 +1647,8 @@ "reportableChange": 0 }, { - "name": "AcceptedCommandList", - "code": 65529, + "name": "GeneratedCommandList", + "code": 65528, "mfgCode": null, "side": "server", "type": "array", @@ -1576,8 +1663,8 @@ "reportableChange": 0 }, { - "name": "EventList", - "code": 65530, + "name": "AcceptedCommandList", + "code": 65529, "mfgCode": null, "side": "server", "type": "array", @@ -1633,7 +1720,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "1", + "defaultValue": "3", "reportable": 1, "minInterval": 0, "maxInterval": 65344, @@ -1642,15 +1729,15 @@ ] }, { - "name": "General Diagnostics", - "code": 51, + "name": "Diagnostic Logs", + "code": 50, "mfgCode": null, - "define": "GENERAL_DIAGNOSTICS_CLUSTER", + "define": "DIAGNOSTIC_LOGS_CLUSTER", "side": "server", "enabled": 1, "commands": [ { - "name": "TestEventTrigger", + "name": "RetrieveLogsRequest", "code": 0, "mfgCode": null, "source": "client", @@ -1658,17 +1745,9 @@ "isEnabled": 1 }, { - "name": "TimeSnapshot", + "name": "RetrieveLogsResponse", "code": 1, "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "TimeSnapshotResponse", - "code": 2, - "mfgCode": null, "source": "server", "isIncoming": 0, "isEnabled": 1 @@ -1676,8 +1755,8 @@ ], "attributes": [ { - "name": "NetworkInterfaces", - "code": 0, + "name": "GeneratedCommandList", + "code": 65528, "mfgCode": null, "side": "server", "type": "array", @@ -1687,32 +1766,16 @@ "bounded": 0, "defaultValue": null, "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - }, - { - "name": "RebootCount", - "code": 1, - "mfgCode": null, - "side": "server", - "type": "int16u", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, + "minInterval": 1, + "maxInterval": 65534, "reportableChange": 0 }, { - "name": "UpTime", - "code": 2, + "name": "AcceptedCommandList", + "code": 65529, "mfgCode": null, "side": "server", - "type": "int64u", + "type": "array", "included": 1, "storageOption": "External", "singleton": 0, @@ -1724,11 +1787,11 @@ "reportableChange": 0 }, { - "name": "TotalOperationalHours", - "code": 3, + "name": "AttributeList", + "code": 65531, "mfgCode": null, "side": "server", - "type": "int32u", + "type": "array", "included": 1, "storageOption": "External", "singleton": 0, @@ -1740,40 +1803,76 @@ "reportableChange": 0 }, { - "name": "BootReason", - "code": 4, + "name": "FeatureMap", + "code": 65532, "mfgCode": null, "side": "server", - "type": "BootReasonEnum", + "type": "bitmap32", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "TestEventTriggersEnabled", - "code": 8, + "name": "ClusterRevision", + "code": 65533, "mfgCode": null, "side": "server", - "type": "boolean", + "type": "int16u", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "false", + "defaultValue": "1", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 - }, - { - "name": "GeneratedCommandList", - "code": 65528, + } + ] + }, + { + "name": "General Diagnostics", + "code": 51, + "mfgCode": null, + "define": "GENERAL_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "TestEventTrigger", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TimeSnapshot", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TimeSnapshotResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "NetworkInterfaces", + "code": 0, "mfgCode": null, "side": "server", "type": "array", @@ -1783,13 +1882,93 @@ "bounded": 0, "defaultValue": null, "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RebootCount", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "UpTime", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "AcceptedCommandList", - "code": 65529, + "name": "TotalOperationalHours", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BootReason", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "BootReasonEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TestEventTriggersEnabled", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "false", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, "mfgCode": null, "side": "server", "type": "array", @@ -1804,8 +1983,8 @@ "reportableChange": 0 }, { - "name": "EventList", - "code": 65530, + "name": "AcceptedCommandList", + "code": 65529, "mfgCode": null, "side": "server", "type": "array", @@ -1879,98 +2058,76 @@ ] }, { - "name": "Wi-Fi Network Diagnostics", - "code": 54, + "name": "Software Diagnostics", + "code": 52, "mfgCode": null, - "define": "WIFI_NETWORK_DIAGNOSTICS_CLUSTER", + "define": "SOFTWARE_DIAGNOSTICS_CLUSTER", "side": "server", "enabled": 1, + "commands": [ + { + "name": "ResetWatermarks", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], "attributes": [ { - "name": "BSSID", + "name": "ThreadMetrics", "code": 0, "mfgCode": null, "side": "server", - "type": "octet_string", + "type": "array", "included": 1, "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": null, "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, + "minInterval": 1, + "maxInterval": 65534, "reportableChange": 0 }, { - "name": "SecurityType", + "name": "CurrentHeapFree", "code": 1, "mfgCode": null, "side": "server", - "type": "SecurityTypeEnum", + "type": "int64u", "included": 1, "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": null, "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, + "minInterval": 1, + "maxInterval": 65534, "reportableChange": 0 }, { - "name": "WiFiVersion", + "name": "CurrentHeapUsed", "code": 2, "mfgCode": null, "side": "server", - "type": "WiFiVersionEnum", + "type": "int64u", "included": 1, "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": null, "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, + "minInterval": 1, + "maxInterval": 65534, "reportableChange": 0 }, { - "name": "ChannelNumber", + "name": "CurrentHeapHighWatermark", "code": 3, "mfgCode": null, "side": "server", - "type": "int16u", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - }, - { - "name": "RSSI", - "code": 4, - "mfgCode": null, - "side": "server", - "type": "int8s", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - }, - { - "name": "CurrentMaxRate", - "code": 11, - "mfgCode": null, - "side": "server", "type": "int64u", "included": 1, "storageOption": "External", @@ -1978,8 +2135,8 @@ "bounded": 0, "defaultValue": null, "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, + "minInterval": 1, + "maxInterval": 65534, "reportableChange": 0 }, { @@ -2014,22 +2171,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -2053,10 +2194,10 @@ "side": "server", "type": "bitmap32", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2074,232 +2215,196 @@ "bounded": 0, "defaultValue": "1", "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, + "minInterval": 1, + "maxInterval": 65534, "reportableChange": 0 } ] }, { - "name": "Administrator Commissioning", - "code": 60, + "name": "Wi-Fi Network Diagnostics", + "code": 54, "mfgCode": null, - "define": "ADMINISTRATOR_COMMISSIONING_CLUSTER", + "define": "WIFI_NETWORK_DIAGNOSTICS_CLUSTER", "side": "server", "enabled": 1, "commands": [ { - "name": "OpenCommissioningWindow", + "name": "ResetCounts", "code": 0, "mfgCode": null, "source": "client", "isIncoming": 1, "isEnabled": 1 - }, - { - "name": "RevokeCommissioning", - "code": 2, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 } ], "attributes": [ { - "name": "WindowStatus", + "name": "BSSID", "code": 0, "mfgCode": null, "side": "server", - "type": "CommissioningWindowStatusEnum", + "type": "octet_string", "included": 1, "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": null, "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, + "minInterval": 0, + "maxInterval": 65344, "reportableChange": 0 }, { - "name": "AdminFabricIndex", + "name": "SecurityType", "code": 1, "mfgCode": null, "side": "server", - "type": "fabric_idx", + "type": "SecurityTypeEnum", "included": 1, "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": null, "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, + "minInterval": 0, + "maxInterval": 65344, "reportableChange": 0 }, { - "name": "AdminVendorId", + "name": "WiFiVersion", "code": 2, "mfgCode": null, "side": "server", - "type": "vendor_id", + "type": "WiFiVersionEnum", "included": 1, "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": null, "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, + "minInterval": 0, + "maxInterval": 65344, "reportableChange": 0 }, { - "name": "FeatureMap", - "code": 65532, + "name": "ChannelNumber", + "code": 3, "mfgCode": null, "side": "server", - "type": "bitmap32", + "type": "int16u", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": null, "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, + "minInterval": 0, + "maxInterval": 65344, "reportableChange": 0 }, { - "name": "ClusterRevision", - "code": 65533, + "name": "RSSI", + "code": 4, "mfgCode": null, "side": "server", - "type": "int16u", + "type": "int8s", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "1", + "defaultValue": null, "reportable": 1, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 - } - ] - }, - { - "name": "Operational Credentials", - "code": 62, - "mfgCode": null, - "define": "OPERATIONAL_CREDENTIALS_CLUSTER", - "side": "server", - "enabled": 1, - "commands": [ - { - "name": "AttestationRequest", - "code": 0, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "AttestationResponse", - "code": 1, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - }, - { - "name": "CertificateChainRequest", - "code": 2, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "CertificateChainResponse", - "code": 3, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - }, - { - "name": "CSRRequest", - "code": 4, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 }, { - "name": "CSRResponse", + "name": "BeaconLostCount", "code": 5, "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 }, { - "name": "AddNOC", + "name": "BeaconRxCount", "code": 6, "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 }, { - "name": "UpdateNOC", + "name": "PacketMulticastRxCount", "code": 7, "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 }, { - "name": "NOCResponse", + "name": "PacketMulticastTxCount", "code": 8, "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 }, { - "name": "UpdateFabricLabel", + "name": "PacketUnicastRxCount", "code": 9, "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 }, { - "name": "RemoveFabric", + "name": "PacketUnicastTxCount", "code": 10, "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "AddTrustedRootCertificate", - "code": 11, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - } - ], - "attributes": [ - { - "name": "NOCs", - "code": 0, - "mfgCode": null, "side": "server", - "type": "array", + "type": "int32u", "included": 1, "storageOption": "External", "singleton": 0, @@ -2311,11 +2416,11 @@ "reportableChange": 0 }, { - "name": "Fabrics", - "code": 1, + "name": "CurrentMaxRate", + "code": 11, "mfgCode": null, "side": "server", - "type": "array", + "type": "int64u", "included": 1, "storageOption": "External", "singleton": 0, @@ -2327,40 +2432,40 @@ "reportableChange": 0 }, { - "name": "SupportedFabrics", - "code": 2, + "name": "OverrunCount", + "code": 12, "mfgCode": null, "side": "server", - "type": "int8u", + "type": "int64u", "included": 1, "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": null, "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, + "minInterval": 1, + "maxInterval": 65534, "reportableChange": 0 }, { - "name": "CommissionedFabrics", - "code": 3, + "name": "GeneratedCommandList", + "code": 65528, "mfgCode": null, "side": "server", - "type": "int8u", + "type": "array", "included": 1, "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": null, "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, + "minInterval": 1, + "maxInterval": 65534, "reportableChange": 0 }, { - "name": "TrustedRootCertificates", - "code": 4, + "name": "AcceptedCommandList", + "code": 65529, "mfgCode": null, "side": "server", "type": "array", @@ -2370,16 +2475,16 @@ "bounded": 0, "defaultValue": null, "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, + "minInterval": 1, + "maxInterval": 65534, "reportableChange": 0 }, { - "name": "CurrentFabricIndex", - "code": 5, + "name": "AttributeList", + "code": 65531, "mfgCode": null, "side": "server", - "type": "int8u", + "type": "array", "included": 1, "storageOption": "External", "singleton": 0, @@ -2400,7 +2505,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": "3", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2422,18 +2527,41 @@ "maxInterval": 65344, "reportableChange": 0 } + ], + "events": [ + { + "name": "Disconnection", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "AssociationFailure", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "ConnectionStatus", + "code": 2, + "mfgCode": null, + "side": "server", + "included": 1 + } ] }, { - "name": "Group Key Management", - "code": 63, + "name": "Administrator Commissioning", + "code": 60, "mfgCode": null, - "define": "GROUP_KEY_MANAGEMENT_CLUSTER", + "define": "ADMINISTRATOR_COMMISSIONING_CLUSTER", "side": "server", "enabled": 1, "commands": [ { - "name": "KeySetWrite", + "name": "OpenCommissioningWindow", "code": 0, "mfgCode": null, "source": "client", @@ -2441,101 +2569,21 @@ "isEnabled": 1 }, { - "name": "KeySetRead", - "code": 1, + "name": "RevokeCommissioning", + "code": 2, "mfgCode": null, "source": "client", "isIncoming": 1, "isEnabled": 1 - }, + } + ], + "attributes": [ { - "name": "KeySetReadResponse", - "code": 2, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - }, - { - "name": "KeySetRemove", - "code": 3, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "KeySetReadAllIndices", - "code": 4, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "KeySetReadAllIndicesResponse", - "code": 5, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - } - ], - "attributes": [ - { - "name": "GroupKeyMap", + "name": "WindowStatus", "code": 0, "mfgCode": null, "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - }, - { - "name": "GroupTable", - "code": 1, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - }, - { - "name": "MaxGroupsPerFabric", - "code": 2, - "mfgCode": null, - "side": "server", - "type": "int16u", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "MaxGroupKeysPerFabric", - "code": 3, - "mfgCode": null, - "side": "server", - "type": "int16u", + "type": "CommissioningWindowStatusEnum", "included": 1, "storageOption": "External", "singleton": 0, @@ -2547,11 +2595,11 @@ "reportableChange": 0 }, { - "name": "FeatureMap", - "code": 65532, + "name": "AdminFabricIndex", + "code": 1, "mfgCode": null, "side": "server", - "type": "bitmap32", + "type": "fabric_idx", "included": 1, "storageOption": "External", "singleton": 0, @@ -2563,106 +2611,17 @@ "reportableChange": 0 }, { - "name": "ClusterRevision", - "code": 65533, + "name": "AdminVendorId", + "code": 2, "mfgCode": null, "side": "server", - "type": "int16u", + "type": "vendor_id", "included": 1, "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": null, "reportable": 1, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - } - ] - } - ] - }, - { - "id": 2, - "name": "Anonymous Endpoint Type", - "deviceTypeRef": { - "code": 115, - "profileId": 259, - "label": "MA-laundry-washer", - "name": "MA-laundry-washer" - }, - "deviceTypes": [ - { - "code": 115, - "profileId": 259, - "label": "MA-laundry-washer", - "name": "MA-laundry-washer" - } - ], - "deviceVersions": [ - 1 - ], - "deviceIdentifiers": [ - 115 - ], - "deviceTypeName": "MA-laundry-washer", - "deviceTypeCode": 115, - "deviceTypeProfileId": 259, - "clusters": [ - { - "name": "Identify", - "code": 3, - "mfgCode": null, - "define": "IDENTIFY_CLUSTER", - "side": "server", - "enabled": 1, - "commands": [ - { - "name": "Identify", - "code": 0, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "TriggerEffect", - "code": 64, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - } - ], - "attributes": [ - { - "name": "IdentifyTime", - "code": 0, - "mfgCode": null, - "side": "server", - "type": "int16u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "0x0", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "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 @@ -2699,22 +2658,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -2757,24 +2700,24 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "4", + "defaultValue": "1", "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, + "minInterval": 0, + "maxInterval": 65344, "reportableChange": 0 } ] }, { - "name": "Groups", - "code": 4, + "name": "Operational Credentials", + "code": 62, "mfgCode": null, - "define": "GROUPS_CLUSTER", + "define": "OPERATIONAL_CREDENTIALS_CLUSTER", "side": "server", "enabled": 1, "commands": [ { - "name": "AddGroup", + "name": "AttestationRequest", "code": 0, "mfgCode": null, "source": "client", @@ -2782,73 +2725,89 @@ "isEnabled": 1 }, { - "name": "AddGroupResponse", - "code": 0, + "name": "AttestationResponse", + "code": 1, "mfgCode": null, "source": "server", "isIncoming": 0, "isEnabled": 1 }, { - "name": "ViewGroup", - "code": 1, + "name": "CertificateChainRequest", + "code": 2, "mfgCode": null, "source": "client", "isIncoming": 1, "isEnabled": 1 }, { - "name": "ViewGroupResponse", - "code": 1, + "name": "CertificateChainResponse", + "code": 3, "mfgCode": null, "source": "server", "isIncoming": 0, "isEnabled": 1 }, { - "name": "GetGroupMembership", - "code": 2, + "name": "CSRRequest", + "code": 4, "mfgCode": null, "source": "client", "isIncoming": 1, "isEnabled": 1 }, { - "name": "GetGroupMembershipResponse", - "code": 2, + "name": "CSRResponse", + "code": 5, "mfgCode": null, "source": "server", "isIncoming": 0, "isEnabled": 1 }, { - "name": "RemoveGroup", - "code": 3, + "name": "AddNOC", + "code": 6, "mfgCode": null, "source": "client", "isIncoming": 1, "isEnabled": 1 }, { - "name": "RemoveGroupResponse", - "code": 3, + "name": "UpdateNOC", + "code": 7, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "NOCResponse", + "code": 8, "mfgCode": null, "source": "server", "isIncoming": 0, "isEnabled": 1 }, { - "name": "RemoveAllGroups", - "code": 4, + "name": "UpdateFabricLabel", + "code": 9, "mfgCode": null, "source": "client", "isIncoming": 1, "isEnabled": 1 }, { - "name": "AddGroupIfIdentifying", - "code": 5, - "mfgCode": null, + "name": "RemoveFabric", + "code": 10, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AddTrustedRootCertificate", + "code": 11, + "mfgCode": null, "source": "client", "isIncoming": 1, "isEnabled": 1 @@ -2856,16 +2815,300 @@ ], "attributes": [ { - "name": "NameSupport", + "name": "NOCs", "code": 0, "mfgCode": null, "side": "server", - "type": "NameSupportBitmap", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Fabrics", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SupportedFabrics", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CommissionedFabrics", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TrustedRootCertificates", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentFabricIndex", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", "included": 1, "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Group Key Management", + "code": 63, + "mfgCode": null, + "define": "GROUP_KEY_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "KeySetWrite", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetRead", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "KeySetRemove", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadAllIndices", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadAllIndicesResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "GroupKeyMap", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "GroupTable", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "MaxGroupsPerFabric", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxGroupKeysPerFabric", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2904,8 +3147,163 @@ "reportableChange": 0 }, { - "name": "EventList", - "code": 65530, + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + } + ] + }, + { + "id": 2, + "name": "Anonymous Endpoint Type", + "deviceTypeRef": { + "code": 115, + "profileId": 259, + "label": "MA-laundry-washer", + "name": "MA-laundry-washer", + "deviceTypeOrder": 0 + }, + "deviceTypes": [ + { + "code": 115, + "profileId": 259, + "label": "MA-laundry-washer", + "name": "MA-laundry-washer", + "deviceTypeOrder": 0 + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 115 + ], + "deviceTypeName": "MA-laundry-washer", + "deviceTypeCode": 115, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TriggerEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "IdentifyTime", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "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": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, "mfgCode": null, "side": "server", "type": "array", @@ -2970,15 +3368,15 @@ ] }, { - "name": "On/Off", - "code": 6, + "name": "Groups", + "code": 4, "mfgCode": null, - "define": "ON_OFF_CLUSTER", + "define": "GROUPS_CLUSTER", "side": "server", "enabled": 1, "commands": [ { - "name": "Off", + "name": "AddGroup", "code": 0, "mfgCode": null, "source": "client", @@ -2986,7 +3384,15 @@ "isEnabled": 1 }, { - "name": "On", + "name": "AddGroupResponse", + "code": 0, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ViewGroup", "code": 1, "mfgCode": null, "source": "client", @@ -2994,7 +3400,15 @@ "isEnabled": 1 }, { - "name": "Toggle", + "name": "ViewGroupResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "GetGroupMembership", "code": 2, "mfgCode": null, "source": "client", @@ -3002,24 +3416,40 @@ "isEnabled": 1 }, { - "name": "OffWithEffect", - "code": 64, + "name": "GetGroupMembershipResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "RemoveGroup", + "code": 3, "mfgCode": null, "source": "client", "isIncoming": 1, "isEnabled": 1 }, { - "name": "OnWithRecallGlobalScene", - "code": 65, + "name": "RemoveGroupResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "RemoveAllGroups", + "code": 4, "mfgCode": null, "source": "client", "isIncoming": 1, "isEnabled": 1 }, { - "name": "OnWithTimedOff", - "code": 66, + "name": "AddGroupIfIdentifying", + "code": 5, "mfgCode": null, "source": "client", "isIncoming": 1, @@ -3028,80 +3458,16 @@ ], "attributes": [ { - "name": "OnOff", + "name": "NameSupport", "code": 0, "mfgCode": null, "side": "server", - "type": "boolean", - "included": 1, - "storageOption": "NVM", - "singleton": 0, - "bounded": 0, - "defaultValue": "0", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "GlobalSceneControl", - "code": 16384, - "mfgCode": null, - "side": "server", - "type": "boolean", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "1", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "OnTime", - "code": 16385, - "mfgCode": null, - "side": "server", - "type": "int16u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "0", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "OffWaitTime", - "code": 16386, - "mfgCode": null, - "side": "server", - "type": "int16u", + "type": "NameSupportBitmap", "included": 1, "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "0", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "StartUpOnOff", - "code": 16387, - "mfgCode": null, - "side": "server", - "type": "StartUpOnOffEnum", - "included": 1, - "storageOption": "NVM", - "singleton": 0, - "bounded": 0, - "defaultValue": "0xFF", + "defaultValue": "", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3139,22 +3505,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -3181,7 +3531,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "1", + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3197,7 +3547,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "5", + "defaultValue": "4", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3206,194 +3556,138 @@ ] }, { - "name": "Descriptor", - "code": 29, + "name": "On/Off", + "code": 6, "mfgCode": null, - "define": "DESCRIPTOR_CLUSTER", + "define": "ON_OFF_CLUSTER", "side": "server", "enabled": 1, - "attributes": [ + "commands": [ { - "name": "DeviceTypeList", + "name": "Off", "code": 0, "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 + "source": "client", + "isIncoming": 1, + "isEnabled": 1 }, { - "name": "ServerList", + "name": "On", "code": 1, "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 + "source": "client", + "isIncoming": 1, + "isEnabled": 1 }, { - "name": "ClientList", + "name": "Toggle", "code": 2, "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "PartsList", - "code": 3, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "GeneratedCommandList", - "code": 65528, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 + "source": "client", + "isIncoming": 1, + "isEnabled": 1 }, { - "name": "AcceptedCommandList", - "code": 65529, + "name": "OffWithEffect", + "code": 64, "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 + "source": "client", + "isIncoming": 1, + "isEnabled": 1 }, { - "name": "EventList", - "code": 65530, + "name": "OnWithRecallGlobalScene", + "code": 65, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "OnWithTimedOff", + "code": 66, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "OnOff", + "code": 0, "mfgCode": null, "side": "server", - "type": "array", + "type": "boolean", "included": 1, - "storageOption": "External", + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "AttributeList", - "code": 65531, + "name": "GlobalSceneControl", + "code": 16384, "mfgCode": null, "side": "server", - "type": "array", + "type": "boolean", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "1", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "FeatureMap", - "code": 65532, + "name": "OnTime", + "code": 16385, "mfgCode": null, "side": "server", - "type": "bitmap32", + "type": "int16u", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "ClusterRevision", - "code": 65533, + "name": "OffWaitTime", + "code": 16386, "mfgCode": null, "side": "server", "type": "int16u", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 - } - ] - }, - { - "name": "Binding", - "code": 30, - "mfgCode": null, - "define": "BINDING_CLUSTER", - "side": "server", - "enabled": 1, - "attributes": [ + }, { - "name": "Binding", - "code": 0, + "name": "StartUpOnOff", + "code": 16387, "mfgCode": null, "side": "server", - "type": "array", + "type": "StartUpOnOffEnum", "included": 1, - "storageOption": "External", + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": null, + "defaultValue": "0xFF", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3431,22 +3725,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "EventList", - "code": 65530, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "AttributeList", "code": 65531, @@ -3473,7 +3751,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": "2", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3489,7 +3767,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "1", + "defaultValue": "6", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3498,80 +3776,64 @@ ] }, { - "name": "Power Source", - "code": 47, + "name": "Descriptor", + "code": 29, "mfgCode": null, - "define": "POWER_SOURCE_CLUSTER", + "define": "DESCRIPTOR_CLUSTER", "side": "server", "enabled": 1, "attributes": [ { - "name": "Status", + "name": "DeviceTypeList", "code": 0, "mfgCode": null, "side": "server", - "type": "PowerSourceStatusEnum", + "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "Order", + "name": "ServerList", "code": 1, "mfgCode": null, "side": "server", - "type": "int8u", + "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "Description", + "name": "ClientList", "code": 2, "mfgCode": null, "side": "server", - "type": "char_string", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "WiredCurrentType", - "code": 5, - "mfgCode": null, - "side": "server", - "type": "WiredCurrentTypeEnum", + "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 }, { - "name": "EndpointList", - "code": 31, + "name": "PartsList", + "code": 3, "mfgCode": null, "side": "server", "type": "array", @@ -3656,10 +3918,10 @@ "side": "server", "type": "bitmap32", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "1", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3672,10 +3934,10 @@ "side": "server", "type": "int16u", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "2", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3684,15 +3946,15 @@ ] }, { - "name": "Fixed Label", - "code": 64, + "name": "Binding", + "code": 30, "mfgCode": null, - "define": "FIXED_LABEL_CLUSTER", + "define": "BINDING_CLUSTER", "side": "server", "enabled": 1, "attributes": [ { - "name": "LabelList", + "name": "Binding", "code": 0, "mfgCode": null, "side": "server", @@ -3806,10 +4068,10 @@ ] }, { - "name": "User Label", - "code": 65, + "name": "Fixed Label", + "code": 64, "mfgCode": null, - "define": "USER_LABEL_CLUSTER", + "define": "FIXED_LABEL_CLUSTER", "side": "server", "enabled": 1, "attributes": [ @@ -3928,60 +4190,18 @@ ] }, { - "name": "Mode Select", - "code": 80, + "name": "User Label", + "code": 65, "mfgCode": null, - "define": "MODE_SELECT_CLUSTER", + "define": "USER_LABEL_CLUSTER", "side": "server", "enabled": 1, - "commands": [ - { - "name": "ChangeToMode", - "code": 0, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - } - ], "attributes": [ { - "name": "Description", + "name": "LabelList", "code": 0, "mfgCode": null, "side": "server", - "type": "char_string", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "StandardNamespace", - "code": 1, - "mfgCode": null, - "side": "server", - "type": "enum16", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "SupportedModes", - "code": 2, - "mfgCode": null, - "side": "server", "type": "array", "included": 1, "storageOption": "External", @@ -3993,54 +4213,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "CurrentMode", - "code": 3, - "mfgCode": null, - "side": "server", - "type": "int8u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "StartUpMode", - "code": 4, - "mfgCode": null, - "side": "server", - "type": "int8u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "OnMode", - "code": 5, - "mfgCode": null, - "side": "server", - "type": "int8u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "GeneratedCommandList", "code": 65528, @@ -4319,7 +4491,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "1", + "defaultValue": "2", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -4881,7 +5053,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "1", + "defaultValue": "2", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -4926,4 +5098,4 @@ "parentEndpointIdentifier": null } ] -} \ No newline at end of file +} diff --git a/examples/laundry-washer-app/nxp/zephyr/CMakeLists.txt b/examples/laundry-washer-app/nxp/zephyr/CMakeLists.txt index 9103b6a5567102..b3a03be0403676 100644 --- a/examples/laundry-washer-app/nxp/zephyr/CMakeLists.txt +++ b/examples/laundry-washer-app/nxp/zephyr/CMakeLists.txt @@ -106,10 +106,9 @@ target_sources(app PRIVATE ${ALL_CLUSTERS_COMMON_DIR}/src/smco-stub.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/bridged-actions-stub.cpp - ${ALL_CLUSTERS_COMMON_DIR}/src/static-supported-modes-manager.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/static-supported-temperature-levels.cpp - ${ALL_CLUSTERS_COMMON_DIR}/src/laundry-washer-mode.cpp + ${LAUNDRY_WASHER_NXP_COMMON_DIR}/main/laundry-washer-mode.cpp ${ALL_CLUSTERS_COMMON_DIR}/src/laundry-washer-controls-delegate-impl.cpp - ${LAUNDRY_WASHER_NXP_COMMON_DIR}/main/operational-state-delegate-impl.cpp + ${ALL_CLUSTERS_COMMON_DIR}/src/operational-state-delegate-impl.cpp ${EXAMPLE_PLATFORM_NXP_COMMON_DIR}/icd/source/ICDUtil.cpp ) From fb24b9035d861716942139046e377749494e72d1 Mon Sep 17 00:00:00 2001 From: Wang Qixiang <43193572+wqx6@users.noreply.github.com> Date: Fri, 29 Nov 2024 16:57:35 +0800 Subject: [PATCH 26/26] Decouple ember-specific functions from descriptor cluster (#36493) * descriptor: decouple from ember * Restyled by clang-format * fix shadow error * fix test build * fix test build * use Client cluster iteration * Restyled by clang-format * fix CI building error * fix android build * review changes * Restyled by clang-format * review changes * some doc changes * Fix the semantic tags iterator and add unit tests for the new functions * Restyled by clang-format * fix clang tidy check * add composition test * Restyled by clang-format * Update src/app/data-model-provider/MetadataTypes.h Co-authored-by: Boris Zbarsky * Update src/app/codegen-data-model-provider/CodegenDataModelProvider.cpp Co-authored-by: Boris Zbarsky --------- Co-authored-by: Restyled.io Co-authored-by: Andrei Litvin Co-authored-by: Boris Zbarsky --- .../common/pigweed/rpc_services/Attributes.h | 2 +- src/app/AttributePathExpandIterator.cpp | 14 +- src/app/InteractionModelEngine.cpp | 16 +- src/app/clusters/descriptor/descriptor.cpp | 109 +++---- .../CodegenDataModelProvider.cpp | 242 ++++++++++++--- .../CodegenDataModelProvider.h | 37 ++- .../CodegenDataModelProvider_Write.cpp | 2 +- .../tests/TestCodegenModelViaMocks.cpp | 287 +++++++++++++++--- src/app/data-model-provider/MetadataTypes.cpp | 6 +- src/app/data-model-provider/MetadataTypes.h | 59 +++- src/app/dynamic_server/DynamicDispatcher.cpp | 23 ++ src/app/reporting/Engine.cpp | 6 +- src/app/tests/test-interaction-model-api.cpp | 42 ++- src/app/tests/test-interaction-model-api.h | 15 +- src/app/util/af-types.h | 2 + src/app/util/attribute-storage.cpp | 14 + src/app/util/attribute-storage.h | 12 + src/app/util/mock/MockNodeConfig.cpp | 22 +- src/app/util/mock/MockNodeConfig.h | 21 +- src/app/util/mock/attribute-storage.cpp | 33 ++ .../tests/data_model/DataModelFixtures.cpp | 42 ++- .../tests/data_model/DataModelFixtures.h | 15 +- 22 files changed, 802 insertions(+), 219 deletions(-) diff --git a/examples/common/pigweed/rpc_services/Attributes.h b/examples/common/pigweed/rpc_services/Attributes.h index 99e348e3a205ba..261831ba9b6223 100644 --- a/examples/common/pigweed/rpc_services/Attributes.h +++ b/examples/common/pigweed/rpc_services/Attributes.h @@ -221,7 +221,7 @@ class Attributes : public pw_rpc::nanopb::Attributes::Service request.operationFlags.Set(app::DataModel::OperationFlags::kInternal); request.subjectDescriptor = &subjectDescriptor; - std::optional info = provider->GetClusterInfo(path); + std::optional info = provider->GetServerClusterInfo(path); if (!info.has_value()) { return ::pw::Status::NotFound(); diff --git a/src/app/AttributePathExpandIterator.cpp b/src/app/AttributePathExpandIterator.cpp index 96aa2772912139..419067db9ddf23 100644 --- a/src/app/AttributePathExpandIterator.cpp +++ b/src/app/AttributePathExpandIterator.cpp @@ -115,13 +115,13 @@ std::optional AttributePathExpandIterator::NextClusterId() { if (mpAttributePath->mValue.HasWildcardClusterId()) { - ClusterEntry entry = mDataModelProvider->FirstCluster(mOutputPath.mEndpointId); + ClusterEntry entry = mDataModelProvider->FirstServerCluster(mOutputPath.mEndpointId); return entry.IsValid() ? std::make_optional(entry.path.mClusterId) : std::nullopt; } // only return a cluster if it is valid const ConcreteClusterPath clusterPath(mOutputPath.mEndpointId, mpAttributePath->mValue.mClusterId); - if (!mDataModelProvider->GetClusterInfo(clusterPath).has_value()) + if (!mDataModelProvider->GetServerClusterInfo(clusterPath).has_value()) { return std::nullopt; } @@ -131,7 +131,7 @@ std::optional AttributePathExpandIterator::NextClusterId() VerifyOrReturnValue(mpAttributePath->mValue.HasWildcardClusterId(), std::nullopt); - ClusterEntry entry = mDataModelProvider->NextCluster(mOutputPath); + ClusterEntry entry = mDataModelProvider->NextServerCluster(mOutputPath); return entry.IsValid() ? std::make_optional(entry.path.mClusterId) : std::nullopt; } @@ -141,8 +141,8 @@ std::optional AttributePathExpandIterator::NextEndpointId() { if (mpAttributePath->mValue.HasWildcardEndpointId()) { - EndpointId id = mDataModelProvider->FirstEndpoint(); - return (id != kInvalidEndpointId) ? std::make_optional(id) : std::nullopt; + EndpointEntry ep = mDataModelProvider->FirstEndpoint(); + return (ep.id != kInvalidEndpointId) ? std::make_optional(ep.id) : std::nullopt; } return mpAttributePath->mValue.mEndpointId; @@ -150,8 +150,8 @@ std::optional AttributePathExpandIterator::NextEndpointId() VerifyOrReturnValue(mpAttributePath->mValue.HasWildcardEndpointId(), std::nullopt); - EndpointId id = mDataModelProvider->NextEndpoint(mOutputPath.mEndpointId); - return (id != kInvalidEndpointId) ? std::make_optional(id) : std::nullopt; + EndpointEntry ep = mDataModelProvider->NextEndpoint(mOutputPath.mEndpointId); + return (ep.id != kInvalidEndpointId) ? std::make_optional(ep.id) : std::nullopt; } void AttributePathExpandIterator::ResetCurrentCluster() diff --git a/src/app/InteractionModelEngine.cpp b/src/app/InteractionModelEngine.cpp index 56acd096611565..78967c6d53c680 100644 --- a/src/app/InteractionModelEngine.cpp +++ b/src/app/InteractionModelEngine.cpp @@ -89,14 +89,14 @@ bool MayHaveAccessibleEventPathForEndpoint(DataModel::Provider * aProvider, Endp aSubjectDescriptor); } - DataModel::ClusterEntry clusterEntry = aProvider->FirstCluster(aEventPath.mEndpointId); + DataModel::ClusterEntry clusterEntry = aProvider->FirstServerCluster(aEventPath.mEndpointId); while (clusterEntry.IsValid()) { if (MayHaveAccessibleEventPathForEndpointAndCluster(clusterEntry.path, aEventPath, aSubjectDescriptor)) { return true; } - clusterEntry = aProvider->NextCluster(clusterEntry.path); + clusterEntry = aProvider->NextServerCluster(clusterEntry.path); } return false; @@ -112,10 +112,9 @@ bool MayHaveAccessibleEventPath(DataModel::Provider * aProvider, const EventPath return MayHaveAccessibleEventPathForEndpoint(aProvider, aEventPath.mEndpointId, aEventPath, subjectDescriptor); } - for (EndpointId endpointId = aProvider->FirstEndpoint(); endpointId != kInvalidEndpointId; - endpointId = aProvider->NextEndpoint(endpointId)) + for (DataModel::EndpointEntry ep = aProvider->FirstEndpoint(); ep.IsValid(); ep = aProvider->NextEndpoint(ep.id)) { - if (MayHaveAccessibleEventPathForEndpoint(aProvider, endpointId, aEventPath, subjectDescriptor)) + if (MayHaveAccessibleEventPathForEndpoint(aProvider, ep.id, aEventPath, subjectDescriptor)) { return true; } @@ -1793,17 +1792,16 @@ Protocols::InteractionModel::Status InteractionModelEngine::CheckCommandExistenc // We failed, figure out why ... // - if (provider->GetClusterInfo(aCommandPath).has_value()) + if (provider->GetServerClusterInfo(aCommandPath).has_value()) { return Protocols::InteractionModel::Status::UnsupportedCommand; // cluster exists, so command is invalid } // At this point either cluster or endpoint does not exist. If we find the endpoint, then the cluster // is invalid - for (EndpointId endpoint = provider->FirstEndpoint(); endpoint != kInvalidEndpointId; - endpoint = provider->NextEndpoint(endpoint)) + for (DataModel::EndpointEntry ep = provider->FirstEndpoint(); ep.IsValid(); ep = provider->NextEndpoint(ep.id)) { - if (endpoint == aCommandPath.mEndpointId) + if (ep.id == aCommandPath.mEndpointId) { // endpoint exists, so cluster is invalid return Protocols::InteractionModel::Status::UnsupportedCluster; diff --git a/src/app/clusters/descriptor/descriptor.cpp b/src/app/clusters/descriptor/descriptor.cpp index a8e50387646d5d..409240e66a8b9e 100644 --- a/src/app/clusters/descriptor/descriptor.cpp +++ b/src/app/clusters/descriptor/descriptor.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -73,19 +75,13 @@ CHIP_ERROR DescriptorAttrAccess::ReadFeatureMap(EndpointId endpoint, AttributeVa CHIP_ERROR DescriptorAttrAccess::ReadTagListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) { return aEncoder.EncodeList([&endpoint](const auto & encoder) -> CHIP_ERROR { - Clusters::Descriptor::Structs::SemanticTagStruct::Type tag; - size_t index = 0; - CHIP_ERROR err = CHIP_NO_ERROR; - while ((err = GetSemanticTagForEndpointAtIndex(endpoint, index, tag)) == CHIP_NO_ERROR) + auto tag = InteractionModelEngine::GetInstance()->GetDataModelProvider()->GetFirstSemanticTag(endpoint); + while (tag.has_value()) { - ReturnErrorOnFailure(encoder.Encode(tag)); - index++; + ReturnErrorOnFailure(encoder.Encode(tag.value())); + tag = InteractionModelEngine::GetInstance()->GetDataModelProvider()->GetNextSemanticTag(endpoint, tag.value()); } - if (err == CHIP_ERROR_NOT_FOUND) - { - return CHIP_NO_ERROR; - } - return err; + return CHIP_NO_ERROR; }); } @@ -93,67 +89,63 @@ CHIP_ERROR DescriptorAttrAccess::ReadPartsAttribute(EndpointId endpoint, Attribu { CHIP_ERROR err = CHIP_NO_ERROR; + auto endpointInfo = InteractionModelEngine::GetInstance()->GetDataModelProvider()->GetEndpointInfo(endpoint); if (endpoint == 0x00) { err = aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { - for (uint16_t index = 0; index < emberAfEndpointCount(); index++) + auto endpointEntry = InteractionModelEngine::GetInstance()->GetDataModelProvider()->FirstEndpoint(); + while (endpointEntry.IsValid()) { - if (emberAfEndpointIndexIsEnabled(index)) + if (endpointEntry.id != 0) { - EndpointId endpointId = emberAfEndpointFromIndex(index); - if (endpointId == 0) - continue; - - ReturnErrorOnFailure(encoder.Encode(endpointId)); + ReturnErrorOnFailure(encoder.Encode(endpointEntry.id)); } + endpointEntry = InteractionModelEngine::GetInstance()->GetDataModelProvider()->NextEndpoint(endpointEntry.id); } - return CHIP_NO_ERROR; }); } - else if (IsFlatCompositionForEndpoint(endpoint)) + else if (endpointInfo.has_value() && + endpointInfo->compositionPattern == DataModel::EndpointCompositionPattern::kFullFamilyPattern) { err = aEncoder.EncodeList([endpoint](const auto & encoder) -> CHIP_ERROR { - for (uint16_t index = 0; index < emberAfEndpointCount(); index++) + auto endpointEntry = InteractionModelEngine::GetInstance()->GetDataModelProvider()->FirstEndpoint(); + while (endpointEntry.IsValid()) { - if (!emberAfEndpointIndexIsEnabled(index)) - continue; - - uint16_t childIndex = index; - while (childIndex != chip::kInvalidListIndex) + EndpointId parentEndpointId = endpointEntry.info.parentId; + while (parentEndpointId != chip::kInvalidEndpointId) { - EndpointId parentEndpointId = emberAfParentEndpointFromIndex(childIndex); - if (parentEndpointId == chip::kInvalidEndpointId) - break; - if (parentEndpointId == endpoint) { - ReturnErrorOnFailure(encoder.Encode(emberAfEndpointFromIndex(index))); + ReturnErrorOnFailure(encoder.Encode(endpointEntry.id)); break; } - - childIndex = emberAfIndexFromEndpoint(parentEndpointId); + auto parentEndpointInfo = + InteractionModelEngine::GetInstance()->GetDataModelProvider()->GetEndpointInfo(parentEndpointId); + if (!parentEndpointInfo.has_value()) + { + break; + } + parentEndpointId = parentEndpointInfo->parentId; } + endpointEntry = InteractionModelEngine::GetInstance()->GetDataModelProvider()->NextEndpoint(endpointEntry.id); } return CHIP_NO_ERROR; }); } - else if (IsTreeCompositionForEndpoint(endpoint)) + else if (endpointInfo.has_value() && endpointInfo->compositionPattern == DataModel::EndpointCompositionPattern::kTreePattern) { err = aEncoder.EncodeList([endpoint](const auto & encoder) -> CHIP_ERROR { - for (uint16_t index = 0; index < emberAfEndpointCount(); index++) + auto endpointEntry = InteractionModelEngine::GetInstance()->GetDataModelProvider()->FirstEndpoint(); + while (endpointEntry.IsValid()) { - if (!emberAfEndpointIndexIsEnabled(index)) - continue; - - EndpointId parentEndpointId = emberAfParentEndpointFromIndex(index); - if (parentEndpointId == endpoint) + if (endpointEntry.info.parentId == endpoint) { - ReturnErrorOnFailure(encoder.Encode(emberAfEndpointFromIndex(index))); + ReturnErrorOnFailure(encoder.Encode(endpointEntry.id)); } + endpointEntry = InteractionModelEngine::GetInstance()->GetDataModelProvider()->NextEndpoint(endpointEntry.id); } - return CHIP_NO_ERROR; }); } @@ -165,16 +157,15 @@ CHIP_ERROR DescriptorAttrAccess::ReadDeviceAttribute(EndpointId endpoint, Attrib { CHIP_ERROR err = aEncoder.EncodeList([&endpoint](const auto & encoder) -> CHIP_ERROR { Descriptor::Structs::DeviceTypeStruct::Type deviceStruct; - CHIP_ERROR err2; - auto deviceTypeList = emberAfDeviceTypeListFromEndpoint(endpoint, err2); - ReturnErrorOnFailure(err2); + auto deviceType = InteractionModelEngine::GetInstance()->GetDataModelProvider()->FirstDeviceType(endpoint); - for (auto & deviceType : deviceTypeList) + while (deviceType.has_value()) { - deviceStruct.deviceType = deviceType.deviceId; - deviceStruct.revision = deviceType.deviceVersion; + deviceStruct.deviceType = deviceType->deviceTypeId; + deviceStruct.revision = deviceType->deviceTypeRevision; ReturnErrorOnFailure(encoder.Encode(deviceStruct)); + deviceType = InteractionModelEngine::GetInstance()->GetDataModelProvider()->NextDeviceType(endpoint, *deviceType); } return CHIP_NO_ERROR; @@ -186,12 +177,24 @@ CHIP_ERROR DescriptorAttrAccess::ReadDeviceAttribute(EndpointId endpoint, Attrib CHIP_ERROR DescriptorAttrAccess::ReadClientServerAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder, bool server) { CHIP_ERROR err = aEncoder.EncodeList([&endpoint, server](const auto & encoder) -> CHIP_ERROR { - uint8_t clusterCount = emberAfClusterCount(endpoint, server); - - for (uint8_t clusterIndex = 0; clusterIndex < clusterCount; clusterIndex++) + if (server) { - const EmberAfCluster * cluster = emberAfGetNthCluster(endpoint, clusterIndex, server); - ReturnErrorOnFailure(encoder.Encode(cluster->clusterId)); + auto clusterEntry = InteractionModelEngine::GetInstance()->GetDataModelProvider()->FirstServerCluster(endpoint); + while (clusterEntry.IsValid()) + { + ReturnErrorOnFailure(encoder.Encode(clusterEntry.path.mClusterId)); + clusterEntry = InteractionModelEngine::GetInstance()->GetDataModelProvider()->NextServerCluster(clusterEntry.path); + } + } + else + { + ConcreteClusterPath clusterPath = + InteractionModelEngine::GetInstance()->GetDataModelProvider()->FirstClientCluster(endpoint); + while (clusterPath.HasValidIds()) + { + ReturnErrorOnFailure(encoder.Encode(clusterPath.mClusterId)); + clusterPath = InteractionModelEngine::GetInstance()->GetDataModelProvider()->NextClientCluster(clusterPath); + } } return CHIP_NO_ERROR; diff --git a/src/app/codegen-data-model-provider/CodegenDataModelProvider.cpp b/src/app/codegen-data-model-provider/CodegenDataModelProvider.cpp index b0815da48e0c08..4eae3de1e247db 100644 --- a/src/app/codegen-data-model-provider/CodegenDataModelProvider.cpp +++ b/src/app/codegen-data-model-provider/CodegenDataModelProvider.cpp @@ -128,10 +128,8 @@ std::variant LoadClusterInfo(const ConcreteC } DataModel::ClusterInfo info(*versionPtr); - // TODO: set entry flags: // info->flags.Set(ClusterQualityFlags::kDiagnosticsData) - return info; } @@ -194,6 +192,23 @@ DataModel::ClusterEntry FirstServerClusterEntry(EndpointId endpointId, const Emb return DataModel::ClusterEntry::kInvalid; } +ClusterId FirstClientClusterId(const EmberAfEndpointType * endpoint, unsigned start_index, unsigned & found_index) +{ + for (unsigned cluster_idx = start_index; cluster_idx < endpoint->clusterCount; cluster_idx++) + { + const EmberAfCluster & cluster = endpoint->cluster[cluster_idx]; + if (!cluster.IsClient()) + { + continue; + } + + found_index = cluster_idx; + return cluster.clusterId; + } + + return kInvalidClusterId; +} + /// Load the attribute information into the specified destination /// /// `info` is assumed to be default-constructed/clear (i.e. this sets flags, but does not reset them). @@ -255,8 +270,8 @@ DataModel::DeviceTypeEntry DeviceTypeEntryFromEmber(const EmberAfDeviceType & ot { DataModel::DeviceTypeEntry entry; - entry.deviceTypeId = other.deviceId; - entry.deviceTypeVersion = other.deviceVersion; + entry.deviceTypeId = other.deviceId; + entry.deviceTypeRevision = other.deviceVersion; return entry; } @@ -265,7 +280,7 @@ DataModel::DeviceTypeEntry DeviceTypeEntryFromEmber(const EmberAfDeviceType & ot // so you must do `a == b` and the `b == a` will not work. bool operator==(const DataModel::DeviceTypeEntry & a, const EmberAfDeviceType & b) { - return (a.deviceTypeId == b.deviceId) && (a.deviceTypeVersion == b.deviceVersion); + return (a.deviceTypeId == b.deviceId) && (a.deviceTypeRevision == b.deviceVersion); } /// Find the `index` where one of the following holds: @@ -300,6 +315,96 @@ unsigned FindNextDeviceTypeIndex(Span types, const Data const ConcreteCommandPath kInvalidCommandPath(kInvalidEndpointId, kInvalidClusterId, kInvalidCommandId); +std::optional GetEndpointInfoAtIndex(uint16_t endpointIndex) +{ + VerifyOrReturnValue(emberAfEndpointIndexIsEnabled(endpointIndex), std::nullopt); + EndpointId parent = emberAfParentEndpointFromIndex(endpointIndex); + if (GetCompositionForEndpointIndex(endpointIndex) == EndpointComposition::kFullFamily) + { + return DataModel::EndpointInfo(parent, DataModel::EndpointCompositionPattern::kFullFamilyPattern); + } + if (GetCompositionForEndpointIndex(endpointIndex) == EndpointComposition::kTree) + { + return DataModel::EndpointInfo(parent, DataModel::EndpointCompositionPattern::kTreePattern); + } + return std::nullopt; +} + +DataModel::EndpointEntry FirstEndpointEntry(unsigned start_index, uint16_t & found_index) +{ + // find the first enabled index after the start index + const uint16_t lastEndpointIndex = emberAfEndpointCount(); + for (uint16_t endpoint_idx = static_cast(start_index); endpoint_idx < lastEndpointIndex; endpoint_idx++) + { + if (emberAfEndpointIndexIsEnabled(endpoint_idx)) + { + found_index = endpoint_idx; + DataModel::EndpointEntry endpointEntry = DataModel::EndpointEntry::kInvalid; + endpointEntry.id = emberAfEndpointFromIndex(endpoint_idx); + auto endpointInfo = GetEndpointInfoAtIndex(endpoint_idx); + // The endpoint info should have value as this endpoint should be valid at this time + VerifyOrDie(endpointInfo.has_value()); + endpointEntry.info = endpointInfo.value(); + return endpointEntry; + } + } + + // No enabled endpoint found. Give up + return DataModel::EndpointEntry::kInvalid; +} + +bool operator==(const DataModel::Provider::SemanticTag & tagA, const DataModel::Provider::SemanticTag & tagB) +{ + // Label is an optional and nullable value of CharSpan. Optional and Nullable have overload for ==, + // But `==` is deleted for CharSpan. Here we only check whether the string is the same. + if (tagA.label.HasValue() != tagB.label.HasValue()) + { + return false; + } + if (tagA.label.HasValue()) + { + if (tagA.label.Value().IsNull() != tagB.label.Value().IsNull()) + { + return false; + } + if (!tagA.label.Value().IsNull()) + { + if (!tagA.label.Value().Value().data_equal(tagB.label.Value().Value())) + { + return false; + } + } + } + return (tagA.tag == tagB.tag) && (tagA.mfgCode == tagB.mfgCode) && (tagA.namespaceID == tagB.namespaceID); +} + +std::optional FindNextSemanticTagIndex(EndpointId endpoint, const DataModel::Provider::SemanticTag & previous, + unsigned hintWherePreviousMayBe) +{ + DataModel::Provider::SemanticTag hintTag; + // Check whether the hint is the previous tag + if (GetSemanticTagForEndpointAtIndex(endpoint, hintWherePreviousMayBe, hintTag) == CHIP_NO_ERROR) + { + if (previous == hintTag) + { + return std::make_optional(hintWherePreviousMayBe + 1); + } + } + // If the hint is not the previous tag, iterate over all the tags to find the index for the previous tag + unsigned index = 0; + // Ensure that the next index is in the range + while (GetSemanticTagForEndpointAtIndex(endpoint, index + 1, hintTag) == CHIP_NO_ERROR && + GetSemanticTagForEndpointAtIndex(endpoint, index, hintTag) == CHIP_NO_ERROR) + { + if (previous == hintTag) + { + return std::make_optional(index + 1); + } + index++; + } + return std::nullopt; +} + } // namespace std::optional CodegenDataModelProvider::EmberCommandListIterator::First(const CommandId * list) @@ -397,21 +502,19 @@ bool CodegenDataModelProvider::EndpointExists(EndpointId endpoint) return (emberAfIndexFromEndpoint(endpoint) != kEmberInvalidEndpointIndex); } -EndpointId CodegenDataModelProvider::FirstEndpoint() +std::optional CodegenDataModelProvider::GetEndpointInfo(EndpointId endpoint) { - // find the first enabled index - const uint16_t lastEndpointIndex = emberAfEndpointCount(); - for (uint16_t endpoint_idx = 0; endpoint_idx < lastEndpointIndex; endpoint_idx++) + std::optional endpoint_idx = TryFindEndpointIndex(endpoint); + if (endpoint_idx.has_value()) { - if (emberAfEndpointIndexIsEnabled(endpoint_idx)) - { - mEndpointIterationHint = endpoint_idx; - return emberAfEndpointFromIndex(endpoint_idx); - } + return GetEndpointInfoAtIndex(static_cast(*endpoint_idx)); } + return std::nullopt; +} - // No enabled endpoint found. Give up - return kInvalidEndpointId; +DataModel::EndpointEntry CodegenDataModelProvider::FirstEndpoint() +{ + return FirstEndpointEntry(0, mEndpointIterationHint); } std::optional CodegenDataModelProvider::TryFindEndpointIndex(EndpointId id) const @@ -434,51 +537,41 @@ std::optional CodegenDataModelProvider::TryFindEndpointIndex(EndpointI return std::make_optional(idx); } -EndpointId CodegenDataModelProvider::NextEndpoint(EndpointId before) +DataModel::EndpointEntry CodegenDataModelProvider::NextEndpoint(EndpointId before) { - const uint16_t lastEndpointIndex = emberAfEndpointCount(); - std::optional before_idx = TryFindEndpointIndex(before); if (!before_idx.has_value()) { - return kInvalidEndpointId; + return DataModel::EndpointEntry::kInvalid; } - - // find the first enabled index - for (uint16_t endpoint_idx = static_cast(*before_idx + 1); endpoint_idx < lastEndpointIndex; endpoint_idx++) - { - if (emberAfEndpointIndexIsEnabled(endpoint_idx)) - { - mEndpointIterationHint = endpoint_idx; - return emberAfEndpointFromIndex(endpoint_idx); - } - } - - // No enabled enpoint after "before" was found, give up - return kInvalidEndpointId; + return FirstEndpointEntry(*before_idx + 1, mEndpointIterationHint); } -DataModel::ClusterEntry CodegenDataModelProvider::FirstCluster(EndpointId endpointId) +DataModel::ClusterEntry CodegenDataModelProvider::FirstServerCluster(EndpointId endpointId) { const EmberAfEndpointType * endpoint = emberAfFindEndpointType(endpointId); VerifyOrReturnValue(endpoint != nullptr, DataModel::ClusterEntry::kInvalid); VerifyOrReturnValue(endpoint->clusterCount > 0, DataModel::ClusterEntry::kInvalid); VerifyOrReturnValue(endpoint->cluster != nullptr, DataModel::ClusterEntry::kInvalid); - return FirstServerClusterEntry(endpointId, endpoint, 0, mClusterIterationHint); + return FirstServerClusterEntry(endpointId, endpoint, 0, mServerClusterIterationHint); } -std::optional CodegenDataModelProvider::TryFindServerClusterIndex(const EmberAfEndpointType * endpoint, - ClusterId id) const +std::optional CodegenDataModelProvider::TryFindClusterIndex(const EmberAfEndpointType * endpoint, ClusterId id, + ClusterSide side) const { const unsigned clusterCount = endpoint->clusterCount; + unsigned hint = side == ClusterSide::kServer ? mServerClusterIterationHint : mClientClusterIterationHint; - if (mClusterIterationHint < clusterCount) + if (hint < clusterCount) { - const EmberAfCluster & cluster = endpoint->cluster[mClusterIterationHint]; - if (cluster.IsServer() && (cluster.clusterId == id)) + const EmberAfCluster & cluster = endpoint->cluster[hint]; + if (((side == ClusterSide::kServer) && cluster.IsServer()) || ((side == ClusterSide::kClient) && cluster.IsClient())) { - return std::make_optional(mClusterIterationHint); + if (cluster.clusterId == id) + { + return std::make_optional(hint); + } } } @@ -488,7 +581,11 @@ std::optional CodegenDataModelProvider::TryFindServerClusterIndex(cons for (unsigned cluster_idx = 0; cluster_idx < clusterCount; cluster_idx++) { const EmberAfCluster & cluster = endpoint->cluster[cluster_idx]; - if (cluster.IsServer() && (cluster.clusterId == id)) + if (((side == ClusterSide::kServer) && !cluster.IsServer()) || ((side == ClusterSide::kClient) && !cluster.IsClient())) + { + continue; + } + if (cluster.clusterId == id) { return std::make_optional(cluster_idx); } @@ -497,7 +594,7 @@ std::optional CodegenDataModelProvider::TryFindServerClusterIndex(cons return std::nullopt; } -DataModel::ClusterEntry CodegenDataModelProvider::NextCluster(const ConcreteClusterPath & before) +DataModel::ClusterEntry CodegenDataModelProvider::NextServerCluster(const ConcreteClusterPath & before) { // TODO: This search still seems slow (ember will loop). Should use index hints as long // as ember API supports it @@ -507,16 +604,16 @@ DataModel::ClusterEntry CodegenDataModelProvider::NextCluster(const ConcreteClus VerifyOrReturnValue(endpoint->clusterCount > 0, DataModel::ClusterEntry::kInvalid); VerifyOrReturnValue(endpoint->cluster != nullptr, DataModel::ClusterEntry::kInvalid); - std::optional cluster_idx = TryFindServerClusterIndex(endpoint, before.mClusterId); + std::optional cluster_idx = TryFindClusterIndex(endpoint, before.mClusterId, ClusterSide::kServer); if (!cluster_idx.has_value()) { return DataModel::ClusterEntry::kInvalid; } - return FirstServerClusterEntry(before.mEndpointId, endpoint, *cluster_idx + 1, mClusterIterationHint); + return FirstServerClusterEntry(before.mEndpointId, endpoint, *cluster_idx + 1, mServerClusterIterationHint); } -std::optional CodegenDataModelProvider::GetClusterInfo(const ConcreteClusterPath & path) +std::optional CodegenDataModelProvider::GetServerClusterInfo(const ConcreteClusterPath & path) { const EmberAfCluster * cluster = FindServerCluster(path); @@ -537,6 +634,35 @@ std::optional CodegenDataModelProvider::GetClusterInfo(c return std::make_optional(std::get(info)); } +ConcreteClusterPath CodegenDataModelProvider::FirstClientCluster(EndpointId endpointId) +{ + const EmberAfEndpointType * endpoint = emberAfFindEndpointType(endpointId); + VerifyOrReturnValue(endpoint != nullptr, ConcreteClusterPath(endpointId, kInvalidClusterId)); + VerifyOrReturnValue(endpoint->clusterCount > 0, ConcreteClusterPath(endpointId, kInvalidClusterId)); + VerifyOrReturnValue(endpoint->cluster != nullptr, ConcreteClusterPath(endpointId, kInvalidClusterId)); + + return ConcreteClusterPath(endpointId, FirstClientClusterId(endpoint, 0, mClientClusterIterationHint)); +} + +ConcreteClusterPath CodegenDataModelProvider::NextClientCluster(const ConcreteClusterPath & before) +{ + // TODO: This search still seems slow (ember will loop). Should use index hints as long + // as ember API supports it + const EmberAfEndpointType * endpoint = emberAfFindEndpointType(before.mEndpointId); + + VerifyOrReturnValue(endpoint != nullptr, ConcreteClusterPath(before.mEndpointId, kInvalidClusterId)); + VerifyOrReturnValue(endpoint->clusterCount > 0, ConcreteClusterPath(before.mEndpointId, kInvalidClusterId)); + VerifyOrReturnValue(endpoint->cluster != nullptr, ConcreteClusterPath(before.mEndpointId, kInvalidClusterId)); + + std::optional cluster_idx = TryFindClusterIndex(endpoint, before.mClusterId, ClusterSide::kClient); + if (!cluster_idx.has_value()) + { + return ConcreteClusterPath(before.mEndpointId, kInvalidClusterId); + } + + return ConcreteClusterPath(before.mEndpointId, FirstClientClusterId(endpoint, *cluster_idx + 1, mClientClusterIterationHint)); +} + DataModel::AttributeEntry CodegenDataModelProvider::FirstAttribute(const ConcreteClusterPath & path) { const EmberAfCluster * cluster = FindServerCluster(path); @@ -772,5 +898,29 @@ std::optional CodegenDataModelProvider::NextDeviceTy return DeviceTypeEntryFromEmber(deviceTypes[idx]); } +std::optional CodegenDataModelProvider::GetFirstSemanticTag(EndpointId endpoint) +{ + Clusters::Descriptor::Structs::SemanticTagStruct::Type tag; + // we start at the beginning + mSemanticTagIterationHint = 0; + if (GetSemanticTagForEndpointAtIndex(endpoint, 0, tag) == CHIP_NO_ERROR) + { + return std::make_optional(tag); + } + return std::nullopt; +} + +std::optional CodegenDataModelProvider::GetNextSemanticTag(EndpointId endpoint, + const SemanticTag & previous) +{ + Clusters::Descriptor::Structs::SemanticTagStruct::Type tag; + std::optional idx = FindNextSemanticTagIndex(endpoint, previous, mSemanticTagIterationHint); + if (idx.has_value() && GetSemanticTagForEndpointAtIndex(endpoint, *idx, tag) == CHIP_NO_ERROR) + { + return std::make_optional(tag); + } + return std::nullopt; +} + } // namespace app } // namespace chip diff --git a/src/app/codegen-data-model-provider/CodegenDataModelProvider.h b/src/app/codegen-data-model-provider/CodegenDataModelProvider.h index 59b91747a0ef07..35193a492f819b 100644 --- a/src/app/codegen-data-model-provider/CodegenDataModelProvider.h +++ b/src/app/codegen-data-model-provider/CodegenDataModelProvider.h @@ -149,17 +149,24 @@ class CodegenDataModelProvider : public chip::app::DataModel::Provider chip::TLV::TLVReader & input_arguments, CommandHandler * handler) override; /// attribute tree iteration - EndpointId FirstEndpoint() override; - EndpointId NextEndpoint(EndpointId before) override; + DataModel::EndpointEntry FirstEndpoint() override; + DataModel::EndpointEntry NextEndpoint(EndpointId before) override; + std::optional GetEndpointInfo(EndpointId endpoint) override; bool EndpointExists(EndpointId endpoint) override; std::optional FirstDeviceType(EndpointId endpoint) override; std::optional NextDeviceType(EndpointId endpoint, const DataModel::DeviceTypeEntry & previous) override; - DataModel::ClusterEntry FirstCluster(EndpointId endpoint) override; - DataModel::ClusterEntry NextCluster(const ConcreteClusterPath & before) override; - std::optional GetClusterInfo(const ConcreteClusterPath & path) override; + std::optional GetFirstSemanticTag(EndpointId endpoint) override; + std::optional GetNextSemanticTag(EndpointId endpoint, const SemanticTag & previous) override; + + DataModel::ClusterEntry FirstServerCluster(EndpointId endpoint) override; + DataModel::ClusterEntry NextServerCluster(const ConcreteClusterPath & before) override; + std::optional GetServerClusterInfo(const ConcreteClusterPath & path) override; + + ConcreteClusterPath FirstClientCluster(EndpointId endpoint) override; + ConcreteClusterPath NextClientCluster(const ConcreteClusterPath & before) override; DataModel::AttributeEntry FirstAttribute(const ConcreteClusterPath & cluster) override; DataModel::AttributeEntry NextAttribute(const ConcreteAttributePath & before) override; @@ -175,10 +182,12 @@ class CodegenDataModelProvider : public chip::app::DataModel::Provider private: // Iteration is often done in a tight loop going through all values. // To avoid N^2 iterations, cache a hint of where something is positioned - uint16_t mEndpointIterationHint = 0; - unsigned mClusterIterationHint = 0; - unsigned mAttributeIterationHint = 0; - unsigned mDeviceTypeIterationHint = 0; + uint16_t mEndpointIterationHint = 0; + unsigned mServerClusterIterationHint = 0; + unsigned mClientClusterIterationHint = 0; + unsigned mAttributeIterationHint = 0; + unsigned mDeviceTypeIterationHint = 0; + unsigned mSemanticTagIterationHint = 0; EmberCommandListIterator mAcceptedCommandsIterator; EmberCommandListIterator mGeneratedCommandsIterator; @@ -191,6 +200,13 @@ class CodegenDataModelProvider : public chip::app::DataModel::Provider ClusterReference(const ConcreteClusterPath p, const EmberAfCluster * c) : path(p), cluster(c) {} }; + + enum class ClusterSide : uint8_t + { + kServer, + kClient, + }; + std::optional mPreviouslyFoundCluster; unsigned mEmberMetadataStructureGeneration = 0; @@ -203,7 +219,8 @@ class CodegenDataModelProvider : public chip::app::DataModel::Provider std::optional TryFindAttributeIndex(const EmberAfCluster * cluster, chip::AttributeId id) const; /// Find the index of the given cluster id - std::optional TryFindServerClusterIndex(const EmberAfEndpointType * endpoint, chip::ClusterId id) const; + std::optional TryFindClusterIndex(const EmberAfEndpointType * endpoint, chip::ClusterId id, + ClusterSide clusterSide) const; /// Find the index of the given endpoint id std::optional TryFindEndpointIndex(chip::EndpointId id) const; diff --git a/src/app/codegen-data-model-provider/CodegenDataModelProvider_Write.cpp b/src/app/codegen-data-model-provider/CodegenDataModelProvider_Write.cpp index de2f8886476707..7dcfe7feccff4d 100644 --- a/src/app/codegen-data-model-provider/CodegenDataModelProvider_Write.cpp +++ b/src/app/codegen-data-model-provider/CodegenDataModelProvider_Write.cpp @@ -190,7 +190,7 @@ DataModel::ActionReturnStatus CodegenDataModelProvider::WriteAttribute(const Dat if (request.path.mDataVersion.HasValue()) { - std::optional clusterInfo = GetClusterInfo(request.path); + std::optional clusterInfo = GetServerClusterInfo(request.path); if (!clusterInfo.has_value()) { ChipLogError(DataManagement, "Unable to get cluster info for Endpoint 0x%x, Cluster " ChipLogFormatMEI, diff --git a/src/app/codegen-data-model-provider/tests/TestCodegenModelViaMocks.cpp b/src/app/codegen-data-model-provider/tests/TestCodegenModelViaMocks.cpp index c9b2a1b99a375c..50d8ec67df3deb 100644 --- a/src/app/codegen-data-model-provider/tests/TestCodegenModelViaMocks.cpp +++ b/src/app/codegen-data-model-provider/tests/TestCodegenModelViaMocks.cpp @@ -96,6 +96,17 @@ constexpr uint8_t kDeviceTypeId2Version = 11; constexpr DeviceTypeId kDeviceTypeId3 = 3; constexpr uint8_t kDeviceTypeId3Version = 33; +constexpr uint8_t kNamespaceID1 = 123; +constexpr uint8_t kTag1 = 10; +constexpr char kLabel1[] = "Label1"; + +constexpr uint8_t kNamespaceID2 = 254; +constexpr uint8_t kTag2 = 22; +constexpr char kLabel2[] = "Label2"; + +constexpr uint8_t kNamespaceID3 = 3; +constexpr uint8_t kTag3 = 32; + static_assert(kEndpointIdThatIsMissing != kInvalidEndpointId); static_assert(kEndpointIdThatIsMissing != kMockEndpoint1); static_assert(kEndpointIdThatIsMissing != kMockEndpoint2); @@ -280,10 +291,16 @@ const MockNodeConfig gTestNodeConfig({ MockClusterConfig(MockClusterId(2), { ClusterRevision::Id, FeatureMap::Id, MockAttributeId(1), }), + MockClusterConfig(MockClusterId(3), {}, {}, {}, {}, BitMask().Set(MockClusterSide::kClient)), + MockClusterConfig(MockClusterId(4), {}, {}, {}, {}, BitMask().Set(MockClusterSide::kClient)), }, { { kDeviceTypeId1, kDeviceTypeId1Version}, { kDeviceTypeId2, kDeviceTypeId2Version}, { kDeviceTypeId3, kDeviceTypeId3Version}, + },{ + { MakeNullable(VendorId::TestVendor1), kNamespaceID1, kTag1, MakeOptional(MakeNullable(CharSpan::fromCharString(kLabel1)))}, + { Nullable(), kNamespaceID2, kTag2, MakeOptional(MakeNullable(CharSpan::fromCharString(kLabel2)))}, + { MakeNullable(VendorId::TestVendor3), kNamespaceID3, kTag3, NullOptional}, }), MockEndpointConfig(kMockEndpoint2, { MockClusterConfig(MockClusterId(1), { @@ -308,11 +325,14 @@ const MockNodeConfig gTestNodeConfig({ }, /* attributes */ {}, /* events */ {11}, /* acceptedCommands */ - {4, 6} /* generatedCommands */ + {4, 6}, /* generatedCommands */ + BitMask().Set(MockClusterSide::kClient).Set(MockClusterSide::kServer) ), + MockClusterConfig(MockClusterId(4), {}, {}, {}, {}, MockClusterSide::kClient), }, { { kDeviceTypeId2, kDeviceTypeId2Version}, - }), + }, {}, + EndpointComposition::kTree), MockEndpointConfig(kMockEndpoint3, { MockClusterConfig(MockClusterId(1), { ClusterRevision::Id, FeatureMap::Id, MockAttributeId(1), @@ -875,43 +895,109 @@ TEST(TestCodegenModelViaMocks, IterateOverEndpoints) CodegenDataModelProviderWithContext model; // This iteration relies on the hard-coding that occurs when mock_ember is used - EXPECT_EQ(model.FirstEndpoint(), kMockEndpoint1); - EXPECT_EQ(model.NextEndpoint(kMockEndpoint1), kMockEndpoint2); - EXPECT_EQ(model.NextEndpoint(kMockEndpoint2), kMockEndpoint3); - EXPECT_EQ(model.NextEndpoint(kMockEndpoint3), kInvalidEndpointId); + EndpointEntry ep = model.FirstEndpoint(); + EXPECT_EQ(ep.id, kMockEndpoint1); + EXPECT_EQ(ep.info.parentId, kInvalidEndpointId); + EXPECT_EQ(ep.info.compositionPattern, EndpointCompositionPattern::kFullFamilyPattern); + ep = model.NextEndpoint(kMockEndpoint1); + EXPECT_EQ(ep.id, kMockEndpoint2); + EXPECT_EQ(ep.info.parentId, kInvalidEndpointId); + EXPECT_EQ(ep.info.compositionPattern, EndpointCompositionPattern::kTreePattern); + ep = model.NextEndpoint(kMockEndpoint2); + EXPECT_EQ(ep.id, kMockEndpoint3); + EXPECT_EQ(ep.info.parentId, kInvalidEndpointId); + EXPECT_EQ(ep.info.compositionPattern, EndpointCompositionPattern::kFullFamilyPattern); + ep = model.NextEndpoint(kMockEndpoint3); + EXPECT_EQ(ep.id, kInvalidEndpointId); /// Some out of order requests should work as well - EXPECT_EQ(model.NextEndpoint(kMockEndpoint2), kMockEndpoint3); - EXPECT_EQ(model.NextEndpoint(kMockEndpoint2), kMockEndpoint3); - EXPECT_EQ(model.NextEndpoint(kMockEndpoint1), kMockEndpoint2); - EXPECT_EQ(model.NextEndpoint(kMockEndpoint1), kMockEndpoint2); - EXPECT_EQ(model.NextEndpoint(kMockEndpoint2), kMockEndpoint3); - EXPECT_EQ(model.NextEndpoint(kMockEndpoint1), kMockEndpoint2); - EXPECT_EQ(model.NextEndpoint(kMockEndpoint3), kInvalidEndpointId); - EXPECT_EQ(model.NextEndpoint(kMockEndpoint3), kInvalidEndpointId); - EXPECT_EQ(model.FirstEndpoint(), kMockEndpoint1); - EXPECT_EQ(model.FirstEndpoint(), kMockEndpoint1); + ep = model.NextEndpoint(kMockEndpoint2); + EXPECT_EQ(ep.id, kMockEndpoint3); + EXPECT_EQ(ep.info.parentId, kInvalidEndpointId); + EXPECT_EQ(ep.info.compositionPattern, EndpointCompositionPattern::kFullFamilyPattern); + ep = model.NextEndpoint(kMockEndpoint2); + EXPECT_EQ(ep.id, kMockEndpoint3); + EXPECT_EQ(ep.info.parentId, kInvalidEndpointId); + EXPECT_EQ(ep.info.compositionPattern, EndpointCompositionPattern::kFullFamilyPattern); + ep = model.NextEndpoint(kMockEndpoint1); + EXPECT_EQ(ep.id, kMockEndpoint2); + EXPECT_EQ(ep.info.parentId, kInvalidEndpointId); + EXPECT_EQ(ep.info.compositionPattern, EndpointCompositionPattern::kTreePattern); + ep = model.NextEndpoint(kMockEndpoint1); + EXPECT_EQ(ep.id, kMockEndpoint2); + EXPECT_EQ(ep.info.parentId, kInvalidEndpointId); + EXPECT_EQ(ep.info.compositionPattern, EndpointCompositionPattern::kTreePattern); + ep = model.NextEndpoint(kMockEndpoint2); + EXPECT_EQ(ep.id, kMockEndpoint3); + EXPECT_EQ(ep.info.parentId, kInvalidEndpointId); + EXPECT_EQ(ep.info.compositionPattern, EndpointCompositionPattern::kFullFamilyPattern); + ep = model.NextEndpoint(kMockEndpoint1); + EXPECT_EQ(ep.id, kMockEndpoint2); + EXPECT_EQ(ep.info.parentId, kInvalidEndpointId); + EXPECT_EQ(ep.info.compositionPattern, EndpointCompositionPattern::kTreePattern); + ep = model.NextEndpoint(kMockEndpoint3); + EXPECT_EQ(ep.id, kInvalidEndpointId); + ep = model.NextEndpoint(kMockEndpoint3); + EXPECT_EQ(ep.id, kInvalidEndpointId); + ep = model.FirstEndpoint(); + EXPECT_EQ(ep.id, kMockEndpoint1); + EXPECT_EQ(ep.info.parentId, kInvalidEndpointId); + EXPECT_EQ(ep.info.compositionPattern, EndpointCompositionPattern::kFullFamilyPattern); + ep = model.FirstEndpoint(); + EXPECT_EQ(ep.id, kMockEndpoint1); + EXPECT_EQ(ep.info.parentId, kInvalidEndpointId); + EXPECT_EQ(ep.info.compositionPattern, EndpointCompositionPattern::kFullFamilyPattern); + + // invalid endpoiunts + ep = model.NextEndpoint(kInvalidEndpointId); + EXPECT_EQ(ep.id, kInvalidEndpointId); + ep = model.NextEndpoint(987u); + EXPECT_EQ(ep.id, kInvalidEndpointId); +} + +TEST(TestCodegenModelViaMocks, GetEndpointInfo) +{ + UseMockNodeConfig config(gTestNodeConfig); + CodegenDataModelProviderWithContext model; + + std::optional info = model.GetEndpointInfo(kMockEndpoint1); + ASSERT_TRUE(info.has_value()); + EXPECT_EQ(info->parentId, kInvalidEndpointId); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_EQ(info->compositionPattern, // NOLINT(bugprone-unchecked-optional-access) + EndpointCompositionPattern::kFullFamilyPattern); + info = model.GetEndpointInfo(kMockEndpoint2); + ASSERT_TRUE(info.has_value()); + EXPECT_EQ(info->parentId, kInvalidEndpointId); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_EQ(info->compositionPattern, // NOLINT(bugprone-unchecked-optional-access) + EndpointCompositionPattern::kTreePattern); + info = model.GetEndpointInfo(kMockEndpoint3); + ASSERT_TRUE(info.has_value()); + EXPECT_EQ(info->parentId, kInvalidEndpointId); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_EQ(info->compositionPattern, // NOLINT(bugprone-unchecked-optional-access) + EndpointCompositionPattern::kFullFamilyPattern); // invalid endpoiunts - EXPECT_EQ(model.NextEndpoint(kInvalidEndpointId), kInvalidEndpointId); - EXPECT_EQ(model.NextEndpoint(987u), kInvalidEndpointId); + info = model.GetEndpointInfo(kInvalidEndpointId); + EXPECT_FALSE(info.has_value()); + info = model.GetEndpointInfo(987u); + EXPECT_FALSE(info.has_value()); } -TEST(TestCodegenModelViaMocks, IterateOverClusters) +TEST(TestCodegenModelViaMocks, IterateOverServerClusters) { UseMockNodeConfig config(gTestNodeConfig); CodegenDataModelProviderWithContext model; chip::Test::ResetVersion(); - EXPECT_FALSE(model.FirstCluster(kEndpointIdThatIsMissing).path.HasValidIds()); - EXPECT_FALSE(model.FirstCluster(kInvalidEndpointId).path.HasValidIds()); - EXPECT_FALSE(model.NextCluster(ConcreteClusterPath(kInvalidEndpointId, 123)).path.HasValidIds()); - EXPECT_FALSE(model.NextCluster(ConcreteClusterPath(kMockEndpoint1, kInvalidClusterId)).path.HasValidIds()); - EXPECT_FALSE(model.NextCluster(ConcreteClusterPath(kMockEndpoint1, 981u)).path.HasValidIds()); + EXPECT_FALSE(model.FirstServerCluster(kEndpointIdThatIsMissing).path.HasValidIds()); + EXPECT_FALSE(model.FirstServerCluster(kInvalidEndpointId).path.HasValidIds()); + EXPECT_FALSE(model.NextServerCluster(ConcreteClusterPath(kInvalidEndpointId, 123)).path.HasValidIds()); + EXPECT_FALSE(model.NextServerCluster(ConcreteClusterPath(kMockEndpoint1, kInvalidClusterId)).path.HasValidIds()); + EXPECT_FALSE(model.NextServerCluster(ConcreteClusterPath(kMockEndpoint1, 981u)).path.HasValidIds()); // mock endpoint 1 has 2 mock clusters: 1 and 2 - ClusterEntry entry = model.FirstCluster(kMockEndpoint1); + ClusterEntry entry = model.FirstServerCluster(kMockEndpoint1); ASSERT_TRUE(entry.path.HasValidIds()); EXPECT_EQ(entry.path.mEndpointId, kMockEndpoint1); EXPECT_EQ(entry.path.mClusterId, MockClusterId(1)); @@ -920,31 +1006,31 @@ TEST(TestCodegenModelViaMocks, IterateOverClusters) chip::Test::BumpVersion(); - entry = model.NextCluster(entry.path); + entry = model.NextServerCluster(entry.path); ASSERT_TRUE(entry.path.HasValidIds()); EXPECT_EQ(entry.path.mEndpointId, kMockEndpoint1); EXPECT_EQ(entry.path.mClusterId, MockClusterId(2)); EXPECT_EQ(entry.info.dataVersion, 1u); EXPECT_EQ(entry.info.flags.Raw(), 0u); - entry = model.NextCluster(entry.path); + entry = model.NextServerCluster(entry.path); EXPECT_FALSE(entry.path.HasValidIds()); // mock endpoint 3 has 4 mock clusters: 1 through 4 - entry = model.FirstCluster(kMockEndpoint3); + entry = model.FirstServerCluster(kMockEndpoint3); for (uint16_t clusterId = 1; clusterId <= 4; clusterId++) { ASSERT_TRUE(entry.path.HasValidIds()); EXPECT_EQ(entry.path.mEndpointId, kMockEndpoint3); EXPECT_EQ(entry.path.mClusterId, MockClusterId(clusterId)); - entry = model.NextCluster(entry.path); + entry = model.NextServerCluster(entry.path); } EXPECT_FALSE(entry.path.HasValidIds()); // repeat calls should work for (int i = 0; i < 10; i++) { - entry = model.FirstCluster(kMockEndpoint1); + entry = model.FirstServerCluster(kMockEndpoint1); ASSERT_TRUE(entry.path.HasValidIds()); EXPECT_EQ(entry.path.mEndpointId, kMockEndpoint1); EXPECT_EQ(entry.path.mClusterId, MockClusterId(1)); @@ -952,14 +1038,14 @@ TEST(TestCodegenModelViaMocks, IterateOverClusters) for (int i = 0; i < 10; i++) { - ClusterEntry nextEntry = model.NextCluster(entry.path); + ClusterEntry nextEntry = model.NextServerCluster(entry.path); ASSERT_TRUE(nextEntry.path.HasValidIds()); EXPECT_EQ(nextEntry.path.mEndpointId, kMockEndpoint1); EXPECT_EQ(nextEntry.path.mClusterId, MockClusterId(2)); } } -TEST(TestCodegenModelViaMocks, GetClusterInfo) +TEST(TestCodegenModelViaMocks, GetServerClusterInfo) { UseMockNodeConfig config(gTestNodeConfig); @@ -967,24 +1053,78 @@ TEST(TestCodegenModelViaMocks, GetClusterInfo) chip::Test::ResetVersion(); - ASSERT_FALSE(model.GetClusterInfo(ConcreteClusterPath(kInvalidEndpointId, kInvalidClusterId)).has_value()); - ASSERT_FALSE(model.GetClusterInfo(ConcreteClusterPath(kInvalidEndpointId, MockClusterId(1))).has_value()); - ASSERT_FALSE(model.GetClusterInfo(ConcreteClusterPath(kMockEndpoint1, kInvalidClusterId)).has_value()); - ASSERT_FALSE(model.GetClusterInfo(ConcreteClusterPath(kMockEndpoint1, MockClusterId(10))).has_value()); + ASSERT_FALSE(model.GetServerClusterInfo(ConcreteClusterPath(kInvalidEndpointId, kInvalidClusterId)).has_value()); + ASSERT_FALSE(model.GetServerClusterInfo(ConcreteClusterPath(kInvalidEndpointId, MockClusterId(1))).has_value()); + ASSERT_FALSE(model.GetServerClusterInfo(ConcreteClusterPath(kMockEndpoint1, kInvalidClusterId)).has_value()); + ASSERT_FALSE(model.GetServerClusterInfo(ConcreteClusterPath(kMockEndpoint1, MockClusterId(10))).has_value()); // now get the value - std::optional info = model.GetClusterInfo(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))); + std::optional info = model.GetServerClusterInfo(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))); ASSERT_TRUE(info.has_value()); EXPECT_EQ(info->dataVersion, 0u); // NOLINT(bugprone-unchecked-optional-access) EXPECT_EQ(info->flags.Raw(), 0u); // NOLINT(bugprone-unchecked-optional-access) chip::Test::BumpVersion(); - info = model.GetClusterInfo(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))); + info = model.GetServerClusterInfo(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))); ASSERT_TRUE(info.has_value()); EXPECT_EQ(info->dataVersion, 1u); // NOLINT(bugprone-unchecked-optional-access) EXPECT_EQ(info->flags.Raw(), 0u); // NOLINT(bugprone-unchecked-optional-access) } +TEST(TestCodegenModelViaMocks, IterateOverClientClusters) +{ + UseMockNodeConfig config(gTestNodeConfig); + CodegenDataModelProviderWithContext model; + + EXPECT_FALSE(model.FirstClientCluster(kEndpointIdThatIsMissing).HasValidIds()); + EXPECT_FALSE(model.FirstClientCluster(kInvalidEndpointId).HasValidIds()); + EXPECT_FALSE(model.NextClientCluster(ConcreteClusterPath(kInvalidEndpointId, 123)).HasValidIds()); + EXPECT_FALSE(model.NextClientCluster(ConcreteClusterPath(kMockEndpoint1, kInvalidClusterId)).HasValidIds()); + EXPECT_FALSE(model.NextClientCluster(ConcreteClusterPath(kMockEndpoint1, 981u)).HasValidIds()); + + // mock endpoint 1 has 2 mock client clusters: 3 and 4 + ConcreteClusterPath path = model.FirstClientCluster(kMockEndpoint1); + ASSERT_TRUE(path.HasValidIds()); + EXPECT_EQ(path.mEndpointId, kMockEndpoint1); + EXPECT_EQ(path.mClusterId, MockClusterId(3)); + + path = model.NextClientCluster(path); + ASSERT_TRUE(path.HasValidIds()); + EXPECT_EQ(path.mEndpointId, kMockEndpoint1); + EXPECT_EQ(path.mClusterId, MockClusterId(4)); + + path = model.NextClientCluster(path); + EXPECT_FALSE(path.HasValidIds()); + + // mock endpoint 2 has 1 mock client clusters: 3(has server side at the same time) and 4 + path = model.FirstClientCluster(kMockEndpoint2); + for (uint16_t clusterId = 3; clusterId <= 4; clusterId++) + { + ASSERT_TRUE(path.HasValidIds()); + EXPECT_EQ(path.mEndpointId, kMockEndpoint2); + EXPECT_EQ(path.mClusterId, MockClusterId(clusterId)); + path = model.NextClientCluster(path); + } + EXPECT_FALSE(path.HasValidIds()); + + // repeat calls should work + for (int i = 0; i < 10; i++) + { + path = model.FirstClientCluster(kMockEndpoint1); + ASSERT_TRUE(path.HasValidIds()); + EXPECT_EQ(path.mEndpointId, kMockEndpoint1); + EXPECT_EQ(path.mClusterId, MockClusterId(3)); + } + + for (int i = 0; i < 10; i++) + { + ConcreteClusterPath nextPath = model.NextClientCluster(path); + ASSERT_TRUE(nextPath.HasValidIds()); + EXPECT_EQ(nextPath.mEndpointId, kMockEndpoint1); + EXPECT_EQ(nextPath.mClusterId, MockClusterId(4)); + } +} + TEST(TestCodegenModelViaMocks, IterateOverAttributes) { UseMockNodeConfig config(gTestNodeConfig); @@ -2569,15 +2709,15 @@ TEST(TestCodegenModelViaMocks, DeviceTypeIteration) // Mock endpoint 1 has 3 device types std::optional entry = model.FirstDeviceType(kMockEndpoint1); ASSERT_EQ(entry, - std::make_optional(DeviceTypeEntry{ .deviceTypeId = kDeviceTypeId1, .deviceTypeVersion = kDeviceTypeId1Version })); + std::make_optional(DeviceTypeEntry{ .deviceTypeId = kDeviceTypeId1, .deviceTypeRevision = kDeviceTypeId1Version })); // NOLINTNEXTLINE(bugprone-unchecked-optional-access): Assert above that this is not none entry = model.NextDeviceType(kMockEndpoint1, *entry); ASSERT_EQ(entry, - std::make_optional(DeviceTypeEntry{ .deviceTypeId = kDeviceTypeId2, .deviceTypeVersion = kDeviceTypeId2Version })); + std::make_optional(DeviceTypeEntry{ .deviceTypeId = kDeviceTypeId2, .deviceTypeRevision = kDeviceTypeId2Version })); // NOLINTNEXTLINE(bugprone-unchecked-optional-access): Assert above that this is not none entry = model.NextDeviceType(kMockEndpoint1, *entry); ASSERT_EQ(entry, - std::make_optional(DeviceTypeEntry{ .deviceTypeId = kDeviceTypeId3, .deviceTypeVersion = kDeviceTypeId3Version })); + std::make_optional(DeviceTypeEntry{ .deviceTypeId = kDeviceTypeId3, .deviceTypeRevision = kDeviceTypeId3Version })); // NOLINTNEXTLINE(bugprone-unchecked-optional-access): Assert above that this is not none entry = model.NextDeviceType(kMockEndpoint1, *entry); ASSERT_FALSE(entry.has_value()); @@ -2585,19 +2725,19 @@ TEST(TestCodegenModelViaMocks, DeviceTypeIteration) // Mock endpoint 2 has 1 device types entry = model.FirstDeviceType(kMockEndpoint2); ASSERT_EQ(entry, - std::make_optional(DeviceTypeEntry{ .deviceTypeId = kDeviceTypeId2, .deviceTypeVersion = kDeviceTypeId2Version })); + std::make_optional(DeviceTypeEntry{ .deviceTypeId = kDeviceTypeId2, .deviceTypeRevision = kDeviceTypeId2Version })); // NOLINTNEXTLINE(bugprone-unchecked-optional-access): Assert above that this is not none entry = model.NextDeviceType(kMockEndpoint2, *entry); ASSERT_FALSE(entry.has_value()); // out of order query works - entry = std::make_optional(DeviceTypeEntry{ .deviceTypeId = kDeviceTypeId2, .deviceTypeVersion = kDeviceTypeId2Version }); + entry = std::make_optional(DeviceTypeEntry{ .deviceTypeId = kDeviceTypeId2, .deviceTypeRevision = kDeviceTypeId2Version }); entry = model.NextDeviceType(kMockEndpoint1, *entry); ASSERT_EQ(entry, - std::make_optional(DeviceTypeEntry{ .deviceTypeId = kDeviceTypeId3, .deviceTypeVersion = kDeviceTypeId3Version })); + std::make_optional(DeviceTypeEntry{ .deviceTypeId = kDeviceTypeId3, .deviceTypeRevision = kDeviceTypeId3Version })); // invalid query fails - entry = std::make_optional(DeviceTypeEntry{ .deviceTypeId = kDeviceTypeId1, .deviceTypeVersion = kDeviceTypeId1Version }); + entry = std::make_optional(DeviceTypeEntry{ .deviceTypeId = kDeviceTypeId1, .deviceTypeRevision = kDeviceTypeId1Version }); entry = model.NextDeviceType(kMockEndpoint2, *entry); ASSERT_FALSE(entry.has_value()); @@ -2605,3 +2745,60 @@ TEST(TestCodegenModelViaMocks, DeviceTypeIteration) entry = model.FirstDeviceType(kMockEndpoint3); ASSERT_FALSE(entry.has_value()); } + +TEST(TestCodegenModelViaMocks, SemanticTagIteration) +{ + UseMockNodeConfig config(gTestNodeConfig); + CodegenDataModelProviderWithContext model; + + // Mock endpoint 1 has 3 semantic tags + std::optional tag = model.GetFirstSemanticTag(kMockEndpoint1); + ASSERT_TRUE(tag.has_value()); + EXPECT_EQ(tag->mfgCode, MakeNullable(VendorId::TestVendor1)); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_EQ(tag->namespaceID, kNamespaceID1); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_EQ(tag->tag, kTag1); // NOLINT(bugprone-unchecked-optional-access) + ASSERT_TRUE(tag->label.HasValue() && (!tag->label.Value().IsNull())); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_TRUE( + tag->label.Value().Value().data_equal(CharSpan::fromCharString(kLabel1))); // NOLINT(bugprone-unchecked-optional-access) + tag = model.GetNextSemanticTag(kMockEndpoint1, *tag); // NOLINT(bugprone-unchecked-optional-access) + ASSERT_TRUE(tag.has_value()); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_TRUE(tag->mfgCode.IsNull()); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_EQ(tag->namespaceID, kNamespaceID2); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_EQ(tag->tag, kTag2); // NOLINT(bugprone-unchecked-optional-access) + ASSERT_TRUE(tag->label.HasValue() && (!tag->label.Value().IsNull())); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_TRUE( + tag->label.Value().Value().data_equal(CharSpan::fromCharString(kLabel2))); // NOLINT(bugprone-unchecked-optional-access) + tag = model.GetNextSemanticTag(kMockEndpoint1, *tag); // NOLINT(bugprone-unchecked-optional-access) + ASSERT_TRUE(tag.has_value()); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_EQ(tag->mfgCode, MakeNullable(VendorId::TestVendor3)); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_EQ(tag->namespaceID, kNamespaceID3); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_EQ(tag->tag, kTag3); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_FALSE(tag->label.HasValue()); // NOLINT(bugprone-unchecked-optional-access) + tag = model.GetNextSemanticTag(kMockEndpoint1, *tag); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_FALSE(tag.has_value()); + + // out of order query works + DataModel::Provider::SemanticTag existTag = { + .mfgCode = MakeNullable(VendorId::TestVendor1), + .namespaceID = kNamespaceID1, + .tag = kTag1, + .label = MakeOptional(MakeNullable(CharSpan::fromCharString(kLabel1))), + }; + tag = model.GetNextSemanticTag(kMockEndpoint1, existTag); + ASSERT_TRUE(tag.has_value()); + EXPECT_TRUE(tag->mfgCode.IsNull()); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_EQ(tag->namespaceID, kNamespaceID2); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_EQ(tag->tag, kTag2); // NOLINT(bugprone-unchecked-optional-access) + ASSERT_TRUE(tag->label.HasValue() && (!tag->label.Value().IsNull())); // NOLINT(bugprone-unchecked-optional-access) + EXPECT_TRUE( + tag->label.Value().Value().data_equal(CharSpan::fromCharString(kLabel2))); // NOLINT(bugprone-unchecked-optional-access) + + // invalid query fails + existTag.tag = kTag2; + tag = model.GetNextSemanticTag(kMockEndpoint1, existTag); + ASSERT_FALSE(tag.has_value()); + + // empty endpoint works + tag = model.GetFirstSemanticTag(kMockEndpoint2); + ASSERT_FALSE(tag.has_value()); +} diff --git a/src/app/data-model-provider/MetadataTypes.cpp b/src/app/data-model-provider/MetadataTypes.cpp index ed3e2667ddc9d7..2729698c49b1ed 100644 --- a/src/app/data-model-provider/MetadataTypes.cpp +++ b/src/app/data-model-provider/MetadataTypes.cpp @@ -30,12 +30,14 @@ const ClusterEntry ClusterEntry::kInvalid{ .info = ClusterInfo(0 /* version */), // version of invalid cluster entry does not matter }; +const EndpointEntry EndpointEntry::kInvalid{ .id = kInvalidEndpointId, .info = EndpointInfo(kInvalidEndpointId) }; + // A default implementation if just first/next exist bool ProviderMetadataTree::EndpointExists(EndpointId endpoint) { - for (EndpointId id = FirstEndpoint(); id != kInvalidEndpointId; id = NextEndpoint(id)) + for (EndpointEntry ep = FirstEndpoint(); ep.IsValid(); ep = NextEndpoint(ep.id)) { - if (id == endpoint) + if (ep.id == endpoint) { return true; } diff --git a/src/app/data-model-provider/MetadataTypes.h b/src/app/data-model-provider/MetadataTypes.h index c1d173c985ee7a..ab9005412e5261 100644 --- a/src/app/data-model-provider/MetadataTypes.h +++ b/src/app/data-model-provider/MetadataTypes.h @@ -20,16 +20,46 @@ #include #include +#include #include #include #include +#include #include #include +#include namespace chip { namespace app { namespace DataModel { +enum class EndpointCompositionPattern : uint8_t +{ + kTreePattern = 0x1, + kFullFamilyPattern = 0x2, +}; + +struct EndpointInfo +{ + // kInvalidEndpointId if there is no explicit parent endpoint (which means the parent is endpoint 0, + // for endpoints other than endpoint 0). + EndpointId parentId; + EndpointCompositionPattern compositionPattern; + + explicit EndpointInfo(EndpointId parent) : parentId(parent), compositionPattern(EndpointCompositionPattern::kFullFamilyPattern) + {} + explicit EndpointInfo(EndpointId parent, EndpointCompositionPattern pattern) : parentId(parent), compositionPattern(pattern) {} +}; + +struct EndpointEntry +{ + EndpointId id; + EndpointInfo info; + + bool IsValid() const { return id != kInvalidEndpointId; } + static const EndpointEntry kInvalid; +}; + enum class ClusterQualityFlags : uint32_t { kDiagnosticsData = 0x0001, // `K` quality, may be filtered out in subscriptions @@ -111,11 +141,11 @@ struct CommandEntry struct DeviceTypeEntry { DeviceTypeId deviceTypeId; - uint8_t deviceTypeVersion; + uint8_t deviceTypeRevision; bool operator==(const DeviceTypeEntry & other) const { - return (deviceTypeId == other.deviceTypeId) && (deviceTypeVersion == other.deviceTypeVersion); + return (deviceTypeId == other.deviceTypeId) && (deviceTypeRevision == other.deviceTypeRevision); } }; @@ -140,18 +170,31 @@ class ProviderMetadataTree public: virtual ~ProviderMetadataTree() = default; - virtual EndpointId FirstEndpoint() = 0; - virtual EndpointId NextEndpoint(EndpointId before) = 0; + // This iteration will list all the endpoints in the data model + virtual EndpointEntry FirstEndpoint() = 0; + virtual EndpointEntry NextEndpoint(EndpointId before) = 0; + virtual std::optional GetEndpointInfo(EndpointId id) = 0; virtual bool EndpointExists(EndpointId id); // This iteration describes device types registered on an endpoint virtual std::optional FirstDeviceType(EndpointId endpoint) = 0; virtual std::optional NextDeviceType(EndpointId endpoint, const DeviceTypeEntry & previous) = 0; - // This iteration will list all clusters on a given endpoint - virtual ClusterEntry FirstCluster(EndpointId endpoint) = 0; - virtual ClusterEntry NextCluster(const ConcreteClusterPath & before) = 0; - virtual std::optional GetClusterInfo(const ConcreteClusterPath & path) = 0; + // This iteration describes semantic tags registered on an endpoint + using SemanticTag = Clusters::Descriptor::Structs::SemanticTagStruct::Type; + virtual std::optional GetFirstSemanticTag(EndpointId endpoint) = 0; + virtual std::optional GetNextSemanticTag(EndpointId endpoint, const SemanticTag & previous) = 0; + + // This iteration will list all server clusters on a given endpoint + virtual ClusterEntry FirstServerCluster(EndpointId endpoint) = 0; + virtual ClusterEntry NextServerCluster(const ConcreteClusterPath & before) = 0; + virtual std::optional GetServerClusterInfo(const ConcreteClusterPath & path) = 0; + + // This iteration will list all client clusters on a given endpoint + // As the client cluster is only a client without any attributes/commands, + // these functions only return the cluster path. + virtual ConcreteClusterPath FirstClientCluster(EndpointId endpoint) = 0; + virtual ConcreteClusterPath NextClientCluster(const ConcreteClusterPath & before) = 0; // Attribute iteration and accessors provide cluster-level access over // attributes diff --git a/src/app/dynamic_server/DynamicDispatcher.cpp b/src/app/dynamic_server/DynamicDispatcher.cpp index ba4525e2fc7add..634055a9851a6d 100644 --- a/src/app/dynamic_server/DynamicDispatcher.cpp +++ b/src/app/dynamic_server/DynamicDispatcher.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -274,6 +275,28 @@ Protocols::InteractionModel::Status emAfReadOrWriteAttribute(const EmberAfAttrib return Protocols::InteractionModel::Status::UnsupportedAttribute; } +namespace chip { +namespace app { + +EndpointComposition GetCompositionForEndpointIndex(uint16_t endpointIndex) +{ + return EndpointComposition::kFullFamily; +} + +} // namespace app +} // namespace chip + +EndpointId emberAfParentEndpointFromIndex(uint16_t index) +{ + return kInvalidEndpointId; +} + +CHIP_ERROR GetSemanticTagForEndpointAtIndex(EndpointId endpoint, size_t index, + Clusters::Descriptor::Structs::SemanticTagStruct::Type & tag) +{ + return CHIP_ERROR_NOT_FOUND; +} + void emberAfAttributeChanged(EndpointId endpoint, ClusterId clusterId, AttributeId attributeId, AttributesChangedListener * listener) { diff --git a/src/app/reporting/Engine.cpp b/src/app/reporting/Engine.cpp index 63d71bfc92db7a..e2691e519ac13d 100644 --- a/src/app/reporting/Engine.cpp +++ b/src/app/reporting/Engine.cpp @@ -51,7 +51,7 @@ using Protocols::InteractionModel::Status; Status EventPathValid(DataModel::Provider * model, const ConcreteEventPath & eventPath) { - if (!model->GetClusterInfo(eventPath).has_value()) + if (!model->GetServerClusterInfo(eventPath).has_value()) { return model->EndpointExists(eventPath.mEndpointId) ? Status::UnsupportedCluster : Status::UnsupportedEndpoint; } @@ -148,7 +148,7 @@ DataModel::ActionReturnStatus RetrieveClusterData(DataModel::Provider * dataMode readRequest.path = path; DataVersion version = 0; - if (std::optional clusterInfo = dataModel->GetClusterInfo(path); clusterInfo.has_value()) + if (std::optional clusterInfo = dataModel->GetServerClusterInfo(path); clusterInfo.has_value()) { version = clusterInfo->dataVersion; } @@ -208,7 +208,7 @@ DataModel::ActionReturnStatus RetrieveClusterData(DataModel::Provider * dataMode bool IsClusterDataVersionEqualTo(DataModel::Provider * dataModel, const ConcreteClusterPath & path, DataVersion dataVersion) { - std::optional info = dataModel->GetClusterInfo(path); + std::optional info = dataModel->GetServerClusterInfo(path); if (!info.has_value()) { return false; diff --git a/src/app/tests/test-interaction-model-api.cpp b/src/app/tests/test-interaction-model-api.cpp index d263e251d2da7d..867d4c895ebf55 100644 --- a/src/app/tests/test-interaction-model-api.cpp +++ b/src/app/tests/test-interaction-model-api.cpp @@ -149,16 +149,21 @@ std::optional TestImCustomDataModel::Invoke(const InvokeRequ return std::make_optional(CHIP_ERROR_NOT_IMPLEMENTED); } -EndpointId TestImCustomDataModel::FirstEndpoint() +DataModel::EndpointEntry TestImCustomDataModel::FirstEndpoint() { return CodegenDataModelProviderInstance()->FirstEndpoint(); } -EndpointId TestImCustomDataModel::NextEndpoint(EndpointId before) +DataModel::EndpointEntry TestImCustomDataModel::NextEndpoint(EndpointId before) { return CodegenDataModelProviderInstance()->NextEndpoint(before); } +std::optional TestImCustomDataModel::GetEndpointInfo(EndpointId endpoint) +{ + return CodegenDataModelProviderInstance()->GetEndpointInfo(endpoint); +} + std::optional TestImCustomDataModel::FirstDeviceType(EndpointId endpoint) { return std::nullopt; @@ -170,19 +175,40 @@ std::optional TestImCustomDataModel::NextDeviceType( return std::nullopt; } -ClusterEntry TestImCustomDataModel::FirstCluster(EndpointId endpoint) +std::optional TestImCustomDataModel::GetFirstSemanticTag(EndpointId endpoint) +{ + return std::nullopt; +} + +std::optional TestImCustomDataModel::GetNextSemanticTag(EndpointId endpoint, + const SemanticTag & previous) +{ + return std::nullopt; +} + +ClusterEntry TestImCustomDataModel::FirstServerCluster(EndpointId endpoint) +{ + return CodegenDataModelProviderInstance()->FirstServerCluster(endpoint); +} + +ClusterEntry TestImCustomDataModel::NextServerCluster(const ConcreteClusterPath & before) +{ + return CodegenDataModelProviderInstance()->NextServerCluster(before); +} + +std::optional TestImCustomDataModel::GetServerClusterInfo(const ConcreteClusterPath & path) { - return CodegenDataModelProviderInstance()->FirstCluster(endpoint); + return CodegenDataModelProviderInstance()->GetServerClusterInfo(path); } -ClusterEntry TestImCustomDataModel::NextCluster(const ConcreteClusterPath & before) +ConcreteClusterPath TestImCustomDataModel::FirstClientCluster(EndpointId endpoint) { - return CodegenDataModelProviderInstance()->NextCluster(before); + return CodegenDataModelProviderInstance()->FirstClientCluster(endpoint); } -std::optional TestImCustomDataModel::GetClusterInfo(const ConcreteClusterPath & path) +ConcreteClusterPath TestImCustomDataModel::NextClientCluster(const ConcreteClusterPath & before) { - return CodegenDataModelProviderInstance()->GetClusterInfo(path); + return CodegenDataModelProviderInstance()->NextClientCluster(before); } AttributeEntry TestImCustomDataModel::FirstAttribute(const ConcreteClusterPath & cluster) diff --git a/src/app/tests/test-interaction-model-api.h b/src/app/tests/test-interaction-model-api.h index 0e0fd2c0e5b661..d382ccd8090a0a 100644 --- a/src/app/tests/test-interaction-model-api.h +++ b/src/app/tests/test-interaction-model-api.h @@ -110,14 +110,19 @@ class TestImCustomDataModel : public DataModel::Provider std::optional Invoke(const DataModel::InvokeRequest & request, chip::TLV::TLVReader & input_arguments, CommandHandler * handler) override; - EndpointId FirstEndpoint() override; - EndpointId NextEndpoint(EndpointId before) override; + DataModel::EndpointEntry FirstEndpoint() override; + DataModel::EndpointEntry NextEndpoint(EndpointId before) override; + std::optional GetEndpointInfo(EndpointId endpoint) override; std::optional FirstDeviceType(EndpointId endpoint) override; std::optional NextDeviceType(EndpointId endpoint, const DataModel::DeviceTypeEntry & previous) override; - DataModel::ClusterEntry FirstCluster(EndpointId endpoint) override; - DataModel::ClusterEntry NextCluster(const ConcreteClusterPath & before) override; - std::optional GetClusterInfo(const ConcreteClusterPath & path) override; + std::optional GetFirstSemanticTag(EndpointId endpoint) override; + std::optional GetNextSemanticTag(EndpointId endpoint, const SemanticTag & previous) override; + DataModel::ClusterEntry FirstServerCluster(EndpointId endpoint) override; + DataModel::ClusterEntry NextServerCluster(const ConcreteClusterPath & before) override; + std::optional GetServerClusterInfo(const ConcreteClusterPath & path) override; + ConcreteClusterPath FirstClientCluster(EndpointId endpoint) override; + ConcreteClusterPath NextClientCluster(const ConcreteClusterPath & before) override; DataModel::AttributeEntry FirstAttribute(const ConcreteClusterPath & cluster) override; DataModel::AttributeEntry NextAttribute(const ConcreteAttributePath & before) override; std::optional GetAttributeInfo(const ConcreteAttributePath & path) override; diff --git a/src/app/util/af-types.h b/src/app/util/af-types.h index 04275a2515c23c..e3559069ed9df3 100644 --- a/src/app/util/af-types.h +++ b/src/app/util/af-types.h @@ -120,6 +120,8 @@ struct EmberAfCluster uint16_t eventCount; bool IsServer() const { return (mask & CLUSTER_MASK_SERVER) != 0; } + + bool IsClient() const { return (mask & CLUSTER_MASK_CLIENT) != 0; } }; /** diff --git a/src/app/util/attribute-storage.cpp b/src/app/util/attribute-storage.cpp index 4d9cc2368f6900..3df2ba7c6676aa 100644 --- a/src/app/util/attribute-storage.cpp +++ b/src/app/util/attribute-storage.cpp @@ -1415,6 +1415,20 @@ bool IsTreeCompositionForEndpoint(EndpointId endpoint) return emAfEndpoints[index].bitmask.Has(EmberAfEndpointOptions::isTreeComposition); } +EndpointComposition GetCompositionForEndpointIndex(uint16_t endpointIndex) +{ + VerifyOrReturnValue(endpointIndex < ArraySize(emAfEndpoints), EndpointComposition::kInvalid); + if (emAfEndpoints[endpointIndex].bitmask.Has(EmberAfEndpointOptions::isFlatComposition)) + { + return EndpointComposition::kFullFamily; + } + if (emAfEndpoints[endpointIndex].bitmask.Has(EmberAfEndpointOptions::isTreeComposition)) + { + return EndpointComposition::kTree; + } + return EndpointComposition::kInvalid; +} + } // namespace app } // namespace chip diff --git a/src/app/util/attribute-storage.h b/src/app/util/attribute-storage.h index 711f6a7cff768d..6930db7a965ea2 100644 --- a/src/app/util/attribute-storage.h +++ b/src/app/util/attribute-storage.h @@ -378,5 +378,17 @@ bool IsFlatCompositionForEndpoint(EndpointId endpoint); */ bool IsTreeCompositionForEndpoint(EndpointId endpoint); +enum class EndpointComposition : uint8_t +{ + kFullFamily, + kTree, + kInvalid, +}; + +/** + * @brief Returns the composition for a given endpoint index + */ +EndpointComposition GetCompositionForEndpointIndex(uint16_t index); + } // namespace app } // namespace chip diff --git a/src/app/util/mock/MockNodeConfig.cpp b/src/app/util/mock/MockNodeConfig.cpp index c6572ed0aef075..bb919318e3cbb7 100644 --- a/src/app/util/mock/MockNodeConfig.cpp +++ b/src/app/util/mock/MockNodeConfig.cpp @@ -115,7 +115,7 @@ const T * findById(const std::vector & vector, decltype(std::declval().id) MockClusterConfig::MockClusterConfig(ClusterId aId, std::initializer_list aAttributes, std::initializer_list aEvents, std::initializer_list aAcceptedCommands, - std::initializer_list aGeneratedCommands) : + std::initializer_list aGeneratedCommands, BitMask side) : id(aId), attributes(aAttributes), events(aEvents), mEmberCluster{}, mAcceptedCommands(aAcceptedCommands), mGeneratedCommands(aGeneratedCommands) @@ -127,9 +127,17 @@ MockClusterConfig::MockClusterConfig(ClusterId aId, std::initializer_list(attributes.size()); - mEmberCluster.mask = CLUSTER_MASK_SERVER; mEmberCluster.eventCount = static_cast(mEmberEventList.size()); mEmberCluster.eventList = mEmberEventList.data(); @@ -177,9 +185,11 @@ const MockAttributeConfig * MockClusterConfig::attributeById(AttributeId attribu } MockEndpointConfig::MockEndpointConfig(EndpointId aId, std::initializer_list aClusters, - std::initializer_list aDeviceTypes) : + std::initializer_list aDeviceTypes, + std::initializer_list aTags, + app::EndpointComposition aComposition) : id(aId), - clusters(aClusters), mDeviceTypes(aDeviceTypes), mEmberEndpoint{} + composition(aComposition), clusters(aClusters), mDeviceTypes(aDeviceTypes), mSemanticTags(aTags), mEmberEndpoint{} { VerifyOrDie(aClusters.size() < UINT8_MAX); @@ -193,8 +203,8 @@ MockEndpointConfig::MockEndpointConfig(EndpointId aId, std::initializer_list #include +#include #include #include @@ -74,11 +75,18 @@ struct MockEventConfig const EventId id; }; +enum class MockClusterSide : uint8_t +{ + kServer = 0x1, + kClient = 0x2, +}; + struct MockClusterConfig { MockClusterConfig(ClusterId aId, std::initializer_list aAttributes = {}, std::initializer_list aEvents = {}, std::initializer_list aAcceptedCommands = {}, - std::initializer_list aGeneratedCommands = {}); + std::initializer_list aGeneratedCommands = {}, + BitMask side = BitMask().Set(MockClusterSide::kServer)); // Cluster-config is self-referential: mEmberCluster.attributes references mAttributeMetaData.data() MockClusterConfig(const MockClusterConfig & other); @@ -102,7 +110,9 @@ struct MockClusterConfig struct MockEndpointConfig { MockEndpointConfig(EndpointId aId, std::initializer_list aClusters = {}, - std::initializer_list aDeviceTypes = {}); + std::initializer_list aDeviceTypes = {}, + std::initializer_list aTags = {}, + app::EndpointComposition composition = app::EndpointComposition::kFullFamily); // Endpoint-config is self-referential: mEmberEndpoint.clusters references mEmberClusters.data() MockEndpointConfig(const MockEndpointConfig & other); @@ -115,12 +125,19 @@ struct MockEndpointConfig return Span(mDeviceTypes.data(), mDeviceTypes.size()); } + Span semanticTags() const + { + return Span(mSemanticTags.data(), mSemanticTags.size()); + } + const EndpointId id; + const app::EndpointComposition composition; const std::vector clusters; private: std::vector mEmberClusters; std::vector mDeviceTypes; + std::vector mSemanticTags; EmberAfEndpointType mEmberEndpoint; }; diff --git a/src/app/util/mock/attribute-storage.cpp b/src/app/util/mock/attribute-storage.cpp index 57f3d1e5216264..f41ba4de69fb3a 100644 --- a/src/app/util/mock/attribute-storage.cpp +++ b/src/app/util/mock/attribute-storage.cpp @@ -237,6 +237,39 @@ chip::EndpointId emberAfEndpointFromIndex(uint16_t index) return config.endpoints[index].id; } +namespace chip { +namespace app { + +EndpointComposition GetCompositionForEndpointIndex(uint16_t endpointIndex) +{ + return GetMockNodeConfig().endpoints[endpointIndex].composition; +} + +} // namespace app +} // namespace chip + +EndpointId emberAfParentEndpointFromIndex(uint16_t index) +{ + return kInvalidEndpointId; +} + +CHIP_ERROR GetSemanticTagForEndpointAtIndex(EndpointId endpoint, size_t index, + Clusters::Descriptor::Structs::SemanticTagStruct::Type & tag) +{ + auto ep = GetMockNodeConfig().endpointById(endpoint); + + if (ep) + { + auto semanticTags = ep->semanticTags(); + if (index < semanticTags.size()) + { + tag = semanticTags[index]; + return CHIP_NO_ERROR; + } + } + return CHIP_ERROR_NOT_FOUND; +} + chip::Optional emberAfGetNthClusterId(chip::EndpointId endpointId, uint8_t n, bool server) { VerifyOrReturnValue(server, NullOptional); // only server clusters supported diff --git a/src/controller/tests/data_model/DataModelFixtures.cpp b/src/controller/tests/data_model/DataModelFixtures.cpp index 6f42c38a7789e4..7ef9975bdfddcd 100644 --- a/src/controller/tests/data_model/DataModelFixtures.cpp +++ b/src/controller/tests/data_model/DataModelFixtures.cpp @@ -474,16 +474,21 @@ std::optional CustomDataModel::Invoke(const InvokeRequest & return std::nullopt; // handler status is set by the dispatch } -EndpointId CustomDataModel::FirstEndpoint() +DataModel::EndpointEntry CustomDataModel::FirstEndpoint() { return CodegenDataModelProviderInstance()->FirstEndpoint(); } -EndpointId CustomDataModel::NextEndpoint(EndpointId before) +DataModel::EndpointEntry CustomDataModel::NextEndpoint(EndpointId before) { return CodegenDataModelProviderInstance()->NextEndpoint(before); } +std::optional CustomDataModel::GetEndpointInfo(EndpointId endpoint) +{ + return CodegenDataModelProviderInstance()->GetEndpointInfo(endpoint); +} + std::optional CustomDataModel::FirstDeviceType(EndpointId endpoint) { return std::nullopt; @@ -495,19 +500,40 @@ std::optional CustomDataModel::NextDeviceType(Endpoi return std::nullopt; } -ClusterEntry CustomDataModel::FirstCluster(EndpointId endpoint) +std::optional CustomDataModel::GetFirstSemanticTag(EndpointId endpoint) +{ + return std::nullopt; +} + +std::optional CustomDataModel::GetNextSemanticTag(EndpointId endpoint, + const SemanticTag & previous) +{ + return std::nullopt; +} + +ClusterEntry CustomDataModel::FirstServerCluster(EndpointId endpoint) +{ + return CodegenDataModelProviderInstance()->FirstServerCluster(endpoint); +} + +ClusterEntry CustomDataModel::NextServerCluster(const ConcreteClusterPath & before) +{ + return CodegenDataModelProviderInstance()->NextServerCluster(before); +} + +std::optional CustomDataModel::GetServerClusterInfo(const ConcreteClusterPath & path) { - return CodegenDataModelProviderInstance()->FirstCluster(endpoint); + return CodegenDataModelProviderInstance()->GetServerClusterInfo(path); } -ClusterEntry CustomDataModel::NextCluster(const ConcreteClusterPath & before) +ConcreteClusterPath CustomDataModel::FirstClientCluster(EndpointId endpoint) { - return CodegenDataModelProviderInstance()->NextCluster(before); + return CodegenDataModelProviderInstance()->FirstClientCluster(endpoint); } -std::optional CustomDataModel::GetClusterInfo(const ConcreteClusterPath & path) +ConcreteClusterPath CustomDataModel::NextClientCluster(const ConcreteClusterPath & before) { - return CodegenDataModelProviderInstance()->GetClusterInfo(path); + return CodegenDataModelProviderInstance()->NextClientCluster(before); } AttributeEntry CustomDataModel::FirstAttribute(const ConcreteClusterPath & cluster) diff --git a/src/controller/tests/data_model/DataModelFixtures.h b/src/controller/tests/data_model/DataModelFixtures.h index e9b32aead650ee..c8136751c87ea1 100644 --- a/src/controller/tests/data_model/DataModelFixtures.h +++ b/src/controller/tests/data_model/DataModelFixtures.h @@ -122,14 +122,19 @@ class CustomDataModel : public DataModel::Provider std::optional Invoke(const DataModel::InvokeRequest & request, chip::TLV::TLVReader & input_arguments, CommandHandler * handler) override; - EndpointId FirstEndpoint() override; - EndpointId NextEndpoint(EndpointId before) override; + DataModel::EndpointEntry FirstEndpoint() override; + DataModel::EndpointEntry NextEndpoint(EndpointId before) override; + std::optional GetEndpointInfo(EndpointId endpoint) override; std::optional FirstDeviceType(EndpointId endpoint) override; std::optional NextDeviceType(EndpointId endpoint, const DataModel::DeviceTypeEntry & previous) override; - DataModel::ClusterEntry FirstCluster(EndpointId endpoint) override; - DataModel::ClusterEntry NextCluster(const ConcreteClusterPath & before) override; - std::optional GetClusterInfo(const ConcreteClusterPath & path) override; + std::optional GetFirstSemanticTag(EndpointId endpoint) override; + std::optional GetNextSemanticTag(EndpointId endpoint, const SemanticTag & previous) override; + DataModel::ClusterEntry FirstServerCluster(EndpointId endpoint) override; + DataModel::ClusterEntry NextServerCluster(const ConcreteClusterPath & before) override; + std::optional GetServerClusterInfo(const ConcreteClusterPath & path) override; + ConcreteClusterPath FirstClientCluster(EndpointId endpoint) override; + ConcreteClusterPath NextClientCluster(const ConcreteClusterPath & before) override; DataModel::AttributeEntry FirstAttribute(const ConcreteClusterPath & cluster) override; DataModel::AttributeEntry NextAttribute(const ConcreteAttributePath & before) override; std::optional GetAttributeInfo(const ConcreteAttributePath & path) override;